~bzr-pqm/bzr/bzr.dev

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'
1534.7.171 by Aaron Bentley
Implemented stringifying filesystem conflicts
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
1740.2.4 by Aaron Bentley
Update transform tests and docs
833
    def test_set_executability_order(self):
834
        """Ensure that executability behaves the same, no matter what order.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
835
1740.2.4 by Aaron Bentley
Update transform tests and docs
836
        - create file and set executability simultaneously
837
        - create file and set executability afterward
838
        - unsetting the executability of a file whose executability has not been
839
        declared should throw an exception (this may happen when a
840
        merge attempts to create a file with a duplicate ID)
841
        """
842
        transform, root = self.get_transform()
843
        wt = transform._tree
3034.2.1 by Aaron Bentley
Fix is_executable tests for win32
844
        wt.lock_read()
845
        self.addCleanup(wt.unlock)
1740.2.4 by Aaron Bentley
Update transform tests and docs
846
        transform.new_file('set_on_creation', root, 'Set on creation', 'soc',
847
                           True)
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
848
        sac = transform.new_file('set_after_creation', root,
849
                                 'Set after creation', 'sac')
1740.2.4 by Aaron Bentley
Update transform tests and docs
850
        transform.set_executability(True, sac)
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
851
        uws = transform.new_file('unset_without_set', root, 'Unset badly',
852
                                 'uws')
1740.2.4 by Aaron Bentley
Update transform tests and docs
853
        self.assertRaises(KeyError, transform.set_executability, None, uws)
854
        transform.apply()
855
        self.assertTrue(wt.is_executable('soc'))
856
        self.assertTrue(wt.is_executable('sac'))
857
1534.12.2 by Aaron Bentley
Added test for preserving file mode
858
    def test_preserve_mode(self):
859
        """File mode is preserved when replacing content"""
860
        if sys.platform == 'win32':
861
            raise TestSkipped('chmod has no effect on win32')
862
        transform, root = self.get_transform()
863
        transform.new_file('file1', root, 'contents', 'file1-id', True)
864
        transform.apply()
3146.4.12 by Aaron Bentley
Add needed write lock to test
865
        self.wt.lock_write()
866
        self.addCleanup(self.wt.unlock)
1534.12.2 by Aaron Bentley
Added test for preserving file mode
867
        self.assertTrue(self.wt.is_executable('file1-id'))
868
        transform, root = self.get_transform()
869
        file1_id = transform.trans_id_tree_file_id('file1-id')
870
        transform.delete_contents(file1_id)
871
        transform.create_file('contents2', file1_id)
872
        transform.apply()
873
        self.assertTrue(self.wt.is_executable('file1-id'))
874
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
875
    def test__set_mode_stats_correctly(self):
876
        """_set_mode stats to determine file mode."""
877
        if sys.platform == 'win32':
878
            raise TestSkipped('chmod has no effect on win32')
879
880
        stat_paths = []
881
        real_stat = os.stat
882
        def instrumented_stat(path):
883
            stat_paths.append(path)
884
            return real_stat(path)
885
886
        transform, root = self.get_transform()
887
888
        bar1_id = transform.new_file('bar', root, 'bar contents 1\n',
889
                                     file_id='bar-id-1', executable=False)
890
        transform.apply()
891
892
        transform, root = self.get_transform()
893
        bar1_id = transform.trans_id_tree_path('bar')
894
        bar2_id = transform.trans_id_tree_path('bar2')
895
        try:
896
            os.stat = instrumented_stat
897
            transform.create_file('bar2 contents\n', bar2_id, mode_id=bar1_id)
898
        finally:
899
            os.stat = real_stat
900
            transform.finalize()
901
902
        bar1_abspath = self.wt.abspath('bar')
903
        self.assertEqual([bar1_abspath], stat_paths)
904
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
905
    def test_iter_changes(self):
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
906
        self.wt.set_root_id('eert_toor')
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
907
        transform, root = self.get_transform()
908
        transform.new_file('old', root, 'blah', 'id-1', True)
909
        transform.apply()
910
        transform, root = self.get_transform()
911
        try:
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
912
            self.assertEqual([], list(transform.iter_changes()))
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
913
            old = transform.trans_id_tree_file_id('id-1')
914
            transform.unversion_file(old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
915
            self.assertEqual([('id-1', ('old', None), False, (True, False),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
916
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
917
                (True, True))], list(transform.iter_changes()))
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
918
            transform.new_directory('new', root, 'id-1')
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
919
            self.assertEqual([('id-1', ('old', 'new'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
920
                ('eert_toor', 'eert_toor'), ('old', 'new'),
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
921
                ('file', 'directory'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
922
                (True, False))], list(transform.iter_changes()))
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
923
        finally:
924
            transform.finalize()
925
926
    def test_iter_changes_new(self):
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
927
        self.wt.set_root_id('eert_toor')
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
928
        transform, root = self.get_transform()
929
        transform.new_file('old', root, 'blah')
930
        transform.apply()
931
        transform, root = self.get_transform()
932
        try:
933
            old = transform.trans_id_tree_path('old')
934
            transform.version_file('id-1', old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
935
            self.assertEqual([('id-1', (None, 'old'), False, (False, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
936
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
937
                (False, False))], list(transform.iter_changes()))
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
938
        finally:
939
            transform.finalize()
940
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
941
    def test_iter_changes_modifications(self):
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
942
        self.wt.set_root_id('eert_toor')
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
943
        transform, root = self.get_transform()
944
        transform.new_file('old', root, 'blah', 'id-1')
945
        transform.new_file('new', root, 'blah')
946
        transform.new_directory('subdir', root, 'subdir-id')
947
        transform.apply()
948
        transform, root = self.get_transform()
949
        try:
950
            old = transform.trans_id_tree_path('old')
951
            subdir = transform.trans_id_tree_file_id('subdir-id')
952
            new = transform.trans_id_tree_path('new')
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
953
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
954
955
            #content deletion
956
            transform.delete_contents(old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
957
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
958
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', None),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
959
                (False, False))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
960
961
            #content change
962
            transform.create_file('blah', old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
963
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
964
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
965
                (False, False))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
966
            transform.cancel_deletion(old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
967
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
968
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
969
                (False, False))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
970
            transform.cancel_creation(old)
971
972
            # move file_id to a different file
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
973
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
974
            transform.unversion_file(old)
975
            transform.version_file('id-1', new)
976
            transform.adjust_path('old', root, new)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
977
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
978
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
979
                (False, False))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
980
            transform.cancel_versioning(new)
981
            transform._removed_id = set()
982
983
            #execute bit
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
984
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
985
            transform.set_executability(True, old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
986
            self.assertEqual([('id-1', ('old', 'old'), False, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
987
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
988
                (False, True))], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
989
            transform.set_executability(None, old)
990
991
            # filename
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
992
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
993
            transform.adjust_path('new', root, old)
994
            transform._new_parent = {}
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
995
            self.assertEqual([('id-1', ('old', 'new'), False, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
996
                ('eert_toor', 'eert_toor'), ('old', 'new'), ('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._new_name = {}
999
1000
            # parent directory
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1001
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1002
            transform.adjust_path('new', subdir, old)
1003
            transform._new_name = {}
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1004
            self.assertEqual([('id-1', ('old', 'subdir/old'), False,
2255.2.180 by Martin Pool
merge dirstate
1005
                (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.
1006
                ('file', 'file'), (False, False))],
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1007
                list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1008
            transform._new_path = {}
1009
1010
        finally:
1011
            transform.finalize()
1012
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
1013
    def test_iter_changes_modified_bleed(self):
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1014
        self.wt.set_root_id('eert_toor')
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
1015
        """Modified flag should not bleed from one change to another"""
1016
        # unfortunately, we have no guarantee that file1 (which is modified)
1017
        # will be applied before file2.  And if it's applied after file2, it
1018
        # obviously can't bleed into file2's change output.  But for now, it
1019
        # works.
1020
        transform, root = self.get_transform()
1021
        transform.new_file('file1', root, 'blah', 'id-1')
1022
        transform.new_file('file2', root, 'blah', 'id-2')
1023
        transform.apply()
1024
        transform, root = self.get_transform()
1025
        try:
1026
            transform.delete_contents(transform.trans_id_file_id('id-1'))
1027
            transform.set_executability(True,
1028
            transform.trans_id_file_id('id-2'))
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1029
            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
1030
                ('eert_toor', 'eert_toor'), ('file1', u'file1'),
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
1031
                ('file', None), (False, False)),
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
1032
                ('id-2', (u'file2', u'file2'), False, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1033
                ('eert_toor', 'eert_toor'), ('file2', u'file2'),
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
1034
                ('file', 'file'), (False, True))],
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1035
                list(transform.iter_changes()))
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
1036
        finally:
1037
            transform.finalize()
1038
1551.10.37 by Aaron Bentley
recommit of TreeTransform._iter_changes fix with missing files
1039
    def test_iter_changes_move_missing(self):
1040
        """Test moving ids with no files around"""
1041
        self.wt.set_root_id('toor_eert')
1042
        # Need two steps because versioning a non-existant file is a conflict.
1043
        transform, root = self.get_transform()
1044
        transform.new_directory('floater', root, 'floater-id')
1045
        transform.apply()
1046
        transform, root = self.get_transform()
1047
        transform.delete_contents(transform.trans_id_tree_path('floater'))
1048
        transform.apply()
1049
        transform, root = self.get_transform()
1050
        floater = transform.trans_id_tree_path('floater')
1051
        try:
1052
            transform.adjust_path('flitter', root, floater)
1053
            self.assertEqual([('floater-id', ('floater', 'flitter'), False,
1054
            (True, True), ('toor_eert', 'toor_eert'), ('floater', 'flitter'),
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1055
            (None, None), (False, False))], list(transform.iter_changes()))
1551.10.37 by Aaron Bentley
recommit of TreeTransform._iter_changes fix with missing files
1056
        finally:
1057
            transform.finalize()
1058
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1059
    def test_iter_changes_pointless(self):
1060
        """Ensure that no-ops are not treated as modifications"""
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
1061
        self.wt.set_root_id('eert_toor')
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1062
        transform, root = self.get_transform()
1063
        transform.new_file('old', root, 'blah', 'id-1')
1064
        transform.new_directory('subdir', root, 'subdir-id')
1065
        transform.apply()
1066
        transform, root = self.get_transform()
1067
        try:
1068
            old = transform.trans_id_tree_path('old')
1069
            subdir = transform.trans_id_tree_file_id('subdir-id')
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1070
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1071
            transform.delete_contents(subdir)
1072
            transform.create_directory(subdir)
1073
            transform.set_executability(False, old)
1074
            transform.unversion_file(old)
1075
            transform.version_file('id-1', old)
1076
            transform.adjust_path('old', root, old)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1077
            self.assertEqual([], list(transform.iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
1078
        finally:
1079
            transform.finalize()
1534.7.93 by Aaron Bentley
Added text merge test
1080
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1081
    def test_rename_count(self):
1082
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1083
        transform.new_file('name1', root, 'contents')
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1084
        self.assertEqual(transform.rename_count, 0)
1085
        transform.apply()
1086
        self.assertEqual(transform.rename_count, 1)
1087
        transform2, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1088
        transform2.adjust_path('name2', root,
1089
                               transform2.trans_id_tree_path('name1'))
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1090
        self.assertEqual(transform2.rename_count, 0)
1091
        transform2.apply()
1092
        self.assertEqual(transform2.rename_count, 2)
1093
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1094
    def test_change_parent(self):
2502.1.8 by Aaron Bentley
Updates from review comments
1095
        """Ensure that after we change a parent, the results are still right.
1096
1097
        Renames and parent changes on pending transforms can happen as part
1098
        of conflict resolution, and are explicitly permitted by the
1099
        TreeTransform API.
1100
1101
        This test ensures they work correctly with the rename-avoidance
1102
        optimization.
1103
        """
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1104
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1105
        parent1 = transform.new_directory('parent1', root)
1106
        child1 = transform.new_file('child1', parent1, 'contents')
1107
        parent2 = transform.new_directory('parent2', root)
1108
        transform.adjust_path('child1', parent2, child1)
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1109
        transform.apply()
2502.1.8 by Aaron Bentley
Updates from review comments
1110
        self.failIfExists(self.wt.abspath('parent1/child1'))
1111
        self.failUnlessExists(self.wt.abspath('parent2/child1'))
1112
        # rename limbo/new-1 => parent1, rename limbo/new-3 => parent2
1113
        # 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
1114
        self.failUnlessEqual(2, transform.rename_count)
1115
1116
    def test_cancel_parent(self):
1117
        """Cancelling a parent doesn't cause deletion of a non-empty directory
1118
1119
        This is like the test_change_parent, except that we cancel the parent
1120
        before adjusting the path.  The transform must detect that the
1121
        directory is non-empty, and move children to safe locations.
1122
        """
1123
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1124
        parent1 = transform.new_directory('parent1', root)
1125
        child1 = transform.new_file('child1', parent1, 'contents')
1126
        child2 = transform.new_file('child2', parent1, 'contents')
1127
        try:
1128
            transform.cancel_creation(parent1)
1129
        except OSError:
1130
            self.fail('Failed to move child1 before deleting parent1')
1131
        transform.cancel_creation(child2)
1132
        transform.create_directory(parent1)
1133
        try:
1134
            transform.cancel_creation(parent1)
1135
        # If the transform incorrectly believes that child2 is still in
1136
        # parent1's limbo directory, it will try to rename it and fail
1137
        # because was already moved by the first cancel_creation.
1138
        except OSError:
1139
            self.fail('Transform still thinks child2 is a child of parent1')
1140
        parent2 = transform.new_directory('parent2', root)
1141
        transform.adjust_path('child1', parent2, child1)
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1142
        transform.apply()
2502.1.8 by Aaron Bentley
Updates from review comments
1143
        self.failIfExists(self.wt.abspath('parent1'))
1144
        self.failUnlessExists(self.wt.abspath('parent2/child1'))
1145
        # 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
1146
        self.failUnlessEqual(2, transform.rename_count)
1147
1148
    def test_adjust_and_cancel(self):
2502.1.8 by Aaron Bentley
Updates from review comments
1149
        """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
1150
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1151
        parent1 = transform.new_directory('parent1', root)
1152
        child1 = transform.new_file('child1', parent1, 'contents')
1153
        parent2 = transform.new_directory('parent2', root)
1154
        transform.adjust_path('child1', parent2, child1)
1155
        transform.cancel_creation(child1)
2502.1.2 by Aaron Bentley
Make the limited-renames functionality safer in the general case
1156
        try:
2502.1.8 by Aaron Bentley
Updates from review comments
1157
            transform.cancel_creation(parent1)
1158
        # if the transform thinks child1 is still in parent1's limbo
1159
        # 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
1160
        except OSError:
2502.1.8 by Aaron Bentley
Updates from review comments
1161
            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
1162
        transform.finalize()
1163
2502.1.3 by Aaron Bentley
Don't cause errors when creating contents for trans_ids with no parent/name
1164
    def test_noname_contents(self):
2502.1.8 by Aaron Bentley
Updates from review comments
1165
        """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
1166
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1167
        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
1168
        try:
2502.1.8 by Aaron Bentley
Updates from review comments
1169
            transform.create_directory(parent)
2502.1.3 by Aaron Bentley
Don't cause errors when creating contents for trans_ids with no parent/name
1170
        except KeyError:
1171
            self.fail("Can't handle contents with no name")
1172
        transform.finalize()
1173
2502.1.9 by Aaron Bentley
Add additional test for no-name contents
1174
    def test_noname_contents_nested(self):
1175
        """TreeTransform should permit deferring naming files."""
1176
        transform, root = self.get_transform()
1177
        parent = transform.trans_id_file_id('parent-id')
1178
        try:
1179
            transform.create_directory(parent)
1180
        except KeyError:
1181
            self.fail("Can't handle contents with no name")
1182
        child = transform.new_directory('child', parent)
1183
        transform.adjust_path('parent', root, parent)
1184
        transform.apply()
1185
        self.failUnlessExists(self.wt.abspath('parent/child'))
1186
        self.assertEqual(1, transform.rename_count)
1187
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1188
    def test_reuse_name(self):
1189
        """Avoid reusing the same limbo name for different files"""
1190
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1191
        parent = transform.new_directory('parent', root)
1192
        child1 = transform.new_directory('child', parent)
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1193
        try:
2502.1.8 by Aaron Bentley
Updates from review comments
1194
            child2 = transform.new_directory('child', parent)
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1195
        except OSError:
1196
            self.fail('Tranform tried to use the same limbo name twice')
2502.1.8 by Aaron Bentley
Updates from review comments
1197
        transform.adjust_path('child2', parent, child2)
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1198
        transform.apply()
2502.1.8 by Aaron Bentley
Updates from review comments
1199
        # limbo/new-1 => parent, limbo/new-3 => parent/child2
1200
        # child2 is put into top-level limbo because child1 has already
1201
        # claimed the direct limbo path when child2 is created.  There is no
1202
        # advantage in renaming files once they're in top-level limbo, except
1203
        # as part of apply.
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1204
        self.assertEqual(2, transform.rename_count)
1205
1206
    def test_reuse_when_first_moved(self):
1207
        """Don't avoid direct paths when it is safe to use them"""
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)
1211
        transform.adjust_path('child1', parent, child1)
1212
        child2 = transform.new_directory('child', parent)
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1213
        transform.apply()
2502.1.8 by Aaron Bentley
Updates from review comments
1214
        # limbo/new-1 => parent
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1215
        self.assertEqual(1, transform.rename_count)
1216
1217
    def test_reuse_after_cancel(self):
1218
        """Don't avoid direct paths when it is safe to use them"""
1219
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1220
        parent2 = transform.new_directory('parent2', root)
1221
        child1 = transform.new_directory('child1', parent2)
1222
        transform.cancel_creation(parent2)
1223
        transform.create_directory(parent2)
1224
        child2 = transform.new_directory('child1', parent2)
1225
        transform.adjust_path('child2', parent2, child1)
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1226
        transform.apply()
2502.1.8 by Aaron Bentley
Updates from review comments
1227
        # limbo/new-1 => parent2, limbo/new-2 => parent2/child1
2502.1.4 by Aaron Bentley
Ensure we only reuse limbo names appropriately
1228
        self.assertEqual(2, transform.rename_count)
1229
2502.1.7 by Aaron Bentley
Fix finalize deletion ordering
1230
    def test_finalize_order(self):
2502.1.8 by Aaron Bentley
Updates from review comments
1231
        """Finalize must be done in child-to-parent order"""
2502.1.7 by Aaron Bentley
Fix finalize deletion ordering
1232
        transform, root = self.get_transform()
2502.1.8 by Aaron Bentley
Updates from review comments
1233
        parent = transform.new_directory('parent', root)
1234
        child = transform.new_directory('child', parent)
2502.1.7 by Aaron Bentley
Fix finalize deletion ordering
1235
        try:
1236
            transform.finalize()
1237
        except OSError:
2502.1.8 by Aaron Bentley
Updates from review comments
1238
            self.fail('Tried to remove parent before child1')
2502.1.7 by Aaron Bentley
Fix finalize deletion ordering
1239
2502.1.13 by Aaron Bentley
Updates from review
1240
    def test_cancel_with_cancelled_child_should_succeed(self):
2502.1.12 by Aaron Bentley
Avoid renaming children with no content
1241
        transform, root = self.get_transform()
1242
        parent = transform.new_directory('parent', root)
1243
        child = transform.new_directory('child', parent)
1244
        transform.cancel_creation(child)
2502.1.13 by Aaron Bentley
Updates from review
1245
        transform.cancel_creation(parent)
2502.1.12 by Aaron Bentley
Avoid renaming children with no content
1246
        transform.finalize()
1247
3638.3.15 by Vincent Ladeuil
Fix test_case_insensitive_clash to pass on all platforms (renamed too).
1248
    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).
1249
        def tt_helper():
3638.3.17 by Vincent Ladeuil
Fixed as per Aaron's review.
1250
            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).
1251
            tt = TreeTransform(wt)  # TreeTransform obtains write lock
1252
            try:
3638.3.15 by Vincent Ladeuil
Fix test_case_insensitive_clash to pass on all platforms (renamed too).
1253
                foo = tt.new_directory('foo', tt.root)
1254
                tt.new_file('bar', foo, 'foobar')
1255
                baz = tt.new_directory('baz', tt.root)
1256
                tt.new_file('qux', baz, 'quux')
1257
                # Ask for a rename 'foo' -> 'baz'
1258
                tt.adjust_path('baz', tt.root, foo)
3063.1.3 by Aaron Bentley
Update for Linux
1259
                # 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).
1260
                tt.apply(no_conflicts=True)
3063.1.3 by Aaron Bentley
Update for Linux
1261
            except:
3063.1.1 by Alexander Belchenko
Catch OSError 17 (file exists) in final phase of tree transform and show filename to user (#111758).
1262
                wt.unlock()
3063.1.3 by Aaron Bentley
Update for Linux
1263
                raise
3638.3.17 by Vincent Ladeuil
Fixed as per Aaron's review.
1264
        # The rename will fail because the target directory is not empty (but
1265
        # 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).
1266
        err = self.assertRaises(errors.FileExists, tt_helper)
1267
        self.assertContainsRe(str(err),
3638.3.15 by Vincent Ladeuil
Fix test_case_insensitive_clash to pass on all platforms (renamed too).
1268
            "^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).
1269
3063.1.2 by Alexander Belchenko
test for two directories clash
1270
    def test_two_directories_clash(self):
1271
        def tt_helper():
1272
            wt = self.make_branch_and_tree('.')
1273
            tt = TreeTransform(wt)  # TreeTransform obtains write lock
1274
            try:
3063.1.3 by Aaron Bentley
Update for Linux
1275
                foo_1 = tt.new_directory('foo', tt.root)
1276
                tt.new_directory('bar', foo_1)
3638.3.15 by Vincent Ladeuil
Fix test_case_insensitive_clash to pass on all platforms (renamed too).
1277
                # Adding the same directory with a different content
3063.1.3 by Aaron Bentley
Update for Linux
1278
                foo_2 = tt.new_directory('foo', tt.root)
1279
                tt.new_directory('baz', foo_2)
1280
                # Lie to tt that we've already resolved all conflicts.
3063.1.2 by Alexander Belchenko
test for two directories clash
1281
                tt.apply(no_conflicts=True)
3063.1.3 by Aaron Bentley
Update for Linux
1282
            except:
3063.1.2 by Alexander Belchenko
test for two directories clash
1283
                wt.unlock()
3063.1.3 by Aaron Bentley
Update for Linux
1284
                raise
3063.1.2 by Alexander Belchenko
test for two directories clash
1285
        err = self.assertRaises(errors.FileExists, tt_helper)
1286
        self.assertContainsRe(str(err),
1287
            "^File exists: .+/foo")
1288
3100.1.1 by Aaron Bentley
Fix ImmortalLimbo errors when transforms fail
1289
    def test_two_directories_clash_finalize(self):
1290
        def tt_helper():
1291
            wt = self.make_branch_and_tree('.')
1292
            tt = TreeTransform(wt)  # TreeTransform obtains write lock
1293
            try:
1294
                foo_1 = tt.new_directory('foo', tt.root)
1295
                tt.new_directory('bar', foo_1)
3638.3.15 by Vincent Ladeuil
Fix test_case_insensitive_clash to pass on all platforms (renamed too).
1296
                # Adding the same directory with a different content
3100.1.1 by Aaron Bentley
Fix ImmortalLimbo errors when transforms fail
1297
                foo_2 = tt.new_directory('foo', tt.root)
1298
                tt.new_directory('baz', foo_2)
1299
                # Lie to tt that we've already resolved all conflicts.
1300
                tt.apply(no_conflicts=True)
1301
            except:
1302
                tt.finalize()
1303
                raise
1304
        err = self.assertRaises(errors.FileExists, tt_helper)
1305
        self.assertContainsRe(str(err),
1306
            "^File exists: .+/foo")
1307
3535.6.1 by James Westby
Handle a file turning in to a directory in TreeTransform.
1308
    def test_file_to_directory(self):
1309
        wt = self.make_branch_and_tree('.')
3535.6.2 by James Westby
Fixes from review. Thanks Aaron and John.
1310
        self.build_tree(['foo'])
3535.6.1 by James Westby
Handle a file turning in to a directory in TreeTransform.
1311
        wt.add(['foo'])
3590.3.1 by James Westby
Make TreeTransform update the inventory with new kind information.
1312
        wt.commit("one")
3535.6.1 by James Westby
Handle a file turning in to a directory in TreeTransform.
1313
        tt = TreeTransform(wt)
3535.6.2 by James Westby
Fixes from review. Thanks Aaron and John.
1314
        self.addCleanup(tt.finalize)
3535.6.3 by James Westby
Fix the test to not create transform conflicts.
1315
        foo_trans_id = tt.trans_id_tree_path("foo")
1316
        tt.delete_contents(foo_trans_id)
1317
        tt.create_directory(foo_trans_id)
1318
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1319
        tt.create_file(["aa\n"], bar_trans_id)
1320
        tt.version_file("bar-1", bar_trans_id)
3535.6.2 by James Westby
Fixes from review. Thanks Aaron and John.
1321
        tt.apply()
3535.6.1 by James Westby
Handle a file turning in to a directory in TreeTransform.
1322
        self.failUnlessExists("foo/bar")
3590.3.2 by James Westby
Handle ->symlink changes as well.
1323
        wt.lock_read()
1324
        try:
1325
            self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1326
                    "directory")
1327
        finally:
1328
            wt.unlock()
3590.3.1 by James Westby
Make TreeTransform update the inventory with new kind information.
1329
        wt.commit("two")
1330
        changes = wt.changes_from(wt.basis_tree())
1331
        self.assertFalse(changes.has_changed(), changes)
3535.6.1 by James Westby
Handle a file turning in to a directory in TreeTransform.
1332
3590.3.2 by James Westby
Handle ->symlink changes as well.
1333
    def test_file_to_symlink(self):
3590.3.3 by James Westby
Make ->file changes work as well.
1334
        self.requireFeature(SymlinkFeature)
3590.3.2 by James Westby
Handle ->symlink changes as well.
1335
        wt = self.make_branch_and_tree('.')
1336
        self.build_tree(['foo'])
1337
        wt.add(['foo'])
1338
        wt.commit("one")
1339
        tt = TreeTransform(wt)
1340
        self.addCleanup(tt.finalize)
1341
        foo_trans_id = tt.trans_id_tree_path("foo")
1342
        tt.delete_contents(foo_trans_id)
1343
        tt.create_symlink("bar", foo_trans_id)
1344
        tt.apply()
1345
        self.failUnlessExists("foo")
1346
        wt.lock_read()
1347
        self.addCleanup(wt.unlock)
1348
        self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1349
                "symlink")
1350
3590.3.3 by James Westby
Make ->file changes work as well.
1351
    def test_dir_to_file(self):
1352
        wt = self.make_branch_and_tree('.')
1353
        self.build_tree(['foo/', 'foo/bar'])
1354
        wt.add(['foo', 'foo/bar'])
1355
        wt.commit("one")
1356
        tt = TreeTransform(wt)
1357
        self.addCleanup(tt.finalize)
1358
        foo_trans_id = tt.trans_id_tree_path("foo")
1359
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1360
        tt.delete_contents(foo_trans_id)
1361
        tt.delete_versioned(bar_trans_id)
1362
        tt.create_file(["aa\n"], foo_trans_id)
1363
        tt.apply()
1364
        self.failUnlessExists("foo")
1365
        wt.lock_read()
1366
        self.addCleanup(wt.unlock)
1367
        self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1368
                "file")
1369
3590.3.4 by James Westby
Add a test for creating hardlinks as well.
1370
    def test_dir_to_hardlink(self):
3590.3.5 by James Westby
Use HardlinkFeature for the hardlink test.
1371
        self.requireFeature(HardlinkFeature)
3590.3.4 by James Westby
Add a test for creating hardlinks as well.
1372
        wt = self.make_branch_and_tree('.')
1373
        self.build_tree(['foo/', 'foo/bar'])
1374
        wt.add(['foo', 'foo/bar'])
1375
        wt.commit("one")
1376
        tt = TreeTransform(wt)
1377
        self.addCleanup(tt.finalize)
1378
        foo_trans_id = tt.trans_id_tree_path("foo")
1379
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1380
        tt.delete_contents(foo_trans_id)
1381
        tt.delete_versioned(bar_trans_id)
1382
        self.build_tree(['baz'])
1383
        tt.create_hardlink("baz", foo_trans_id)
1384
        tt.apply()
1385
        self.failUnlessExists("foo")
1386
        self.failUnlessExists("baz")
1387
        wt.lock_read()
1388
        self.addCleanup(wt.unlock)
1389
        self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1390
                "file")
1391
3619.2.10 by Aaron Bentley
Compensate for stale entries in TT._needs_rename
1392
    def test_no_final_path(self):
1393
        transform, root = self.get_transform()
1394
        trans_id = transform.trans_id_file_id('foo')
1395
        transform.create_file('bar', trans_id)
1396
        transform.cancel_creation(trans_id)
1397
        transform.apply()
1398
3363.17.24 by Aaron Bentley
Implement create_by_tree
1399
    def test_create_from_tree(self):
1400
        tree1 = self.make_branch_and_tree('tree1')
1401
        self.build_tree_contents([('tree1/foo/',), ('tree1/bar', 'baz')])
1402
        tree1.add(['foo', 'bar'], ['foo-id', 'bar-id'])
1403
        tree2 = self.make_branch_and_tree('tree2')
1404
        tt = TreeTransform(tree2)
1405
        foo_trans_id = tt.create_path('foo', tt.root)
1406
        create_from_tree(tt, foo_trans_id, tree1, 'foo-id')
1407
        bar_trans_id = tt.create_path('bar', tt.root)
1408
        create_from_tree(tt, bar_trans_id, tree1, 'bar-id')
1409
        tt.apply()
1410
        self.assertEqual('directory', osutils.file_kind('tree2/foo'))
1411
        self.assertFileEqual('baz', 'tree2/bar')
1412
3363.17.25 by Aaron Bentley
remove get_inventory_entry, replace with create_from_tree
1413
    def test_create_from_tree_bytes(self):
1414
        """Provided lines are used instead of tree content."""
1415
        tree1 = self.make_branch_and_tree('tree1')
1416
        self.build_tree_contents([('tree1/foo', 'bar'),])
1417
        tree1.add('foo', 'foo-id')
1418
        tree2 = self.make_branch_and_tree('tree2')
1419
        tt = TreeTransform(tree2)
1420
        foo_trans_id = tt.create_path('foo', tt.root)
1421
        create_from_tree(tt, foo_trans_id, tree1, 'foo-id', bytes='qux')
1422
        tt.apply()
1423
        self.assertFileEqual('qux', 'tree2/foo')
1424
1425
    def test_create_from_tree_symlink(self):
3363.17.24 by Aaron Bentley
Implement create_by_tree
1426
        self.requireFeature(SymlinkFeature)
1427
        tree1 = self.make_branch_and_tree('tree1')
1428
        os.symlink('bar', 'tree1/foo')
1429
        tree1.add('foo', 'foo-id')
1430
        tt = TreeTransform(self.make_branch_and_tree('tree2'))
1431
        foo_trans_id = tt.create_path('foo', tt.root)
1432
        create_from_tree(tt, foo_trans_id, tree1, 'foo-id')
1433
        tt.apply()
1434
        self.assertEqual('bar', os.readlink('tree2/foo'))
1435
2502.1.3 by Aaron Bentley
Don't cause errors when creating contents for trans_ids with no parent/name
1436
1534.7.93 by Aaron Bentley
Added text merge test
1437
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).
1438
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1439
    def __init__(self, dirname, root_id):
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
1440
        self.name = dirname
1534.7.93 by Aaron Bentley
Added text merge test
1441
        os.mkdir(dirname)
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
1442
        self.wt = BzrDir.create_standalone_workingtree(dirname)
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1443
        self.wt.set_root_id(root_id)
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
1444
        self.b = self.wt.branch
1534.7.93 by Aaron Bentley
Added text merge test
1445
        self.tt = TreeTransform(self.wt)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
1446
        self.root = self.tt.trans_id_tree_file_id(self.wt.get_root_id())
1534.7.93 by Aaron Bentley
Added text merge test
1447
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
1448
1534.7.95 by Aaron Bentley
Added more text merge tests
1449
def conflict_text(tree, merge):
1450
    template = '%s TREE\n%s%s\n%s%s MERGE-SOURCE\n'
1451
    return template % ('<' * 7, tree, '=' * 7, merge, '>' * 7)
1452
1534.7.93 by Aaron Bentley
Added text merge test
1453
1454
class TestTransformMerge(TestCaseInTempDir):
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
1455
1534.7.93 by Aaron Bentley
Added text merge test
1456
    def test_text_merge(self):
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
1457
        root_id = generate_ids.gen_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1458
        base = TransformGroup("base", root_id)
1534.7.93 by Aaron Bentley
Added text merge test
1459
        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
1460
        base.tt.new_file('b', base.root, 'b1', 'b')
1461
        base.tt.new_file('c', base.root, 'c', 'c')
1462
        base.tt.new_file('d', base.root, 'd', 'd')
1463
        base.tt.new_file('e', base.root, 'e', 'e')
1464
        base.tt.new_file('f', base.root, 'f', 'f')
1534.7.96 by Aaron Bentley
Tested with BASE as directory
1465
        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
1466
        base.tt.new_directory('h', base.root, 'h')
1534.7.93 by Aaron Bentley
Added text merge test
1467
        base.tt.apply()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1468
        other = TransformGroup("other", root_id)
1534.7.93 by Aaron Bentley
Added text merge test
1469
        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
1470
        other.tt.new_file('b', other.root, 'b2', 'b')
1471
        other.tt.new_file('c', other.root, 'c2', 'c')
1472
        other.tt.new_file('d', other.root, 'd', 'd')
1473
        other.tt.new_file('e', other.root, 'e2', 'e')
1474
        other.tt.new_file('f', other.root, 'f', 'f')
1534.7.96 by Aaron Bentley
Tested with BASE as directory
1475
        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
1476
        other.tt.new_file('h', other.root, 'h\ni\nj\nk\n', 'h')
1534.7.99 by Aaron Bentley
Handle non-existent BASE properly
1477
        other.tt.new_file('i', other.root, 'h\ni\nj\nk\n', 'i')
1534.7.93 by Aaron Bentley
Added text merge test
1478
        other.tt.apply()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1479
        this = TransformGroup("this", root_id)
1534.7.93 by Aaron Bentley
Added text merge test
1480
        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
1481
        this.tt.new_file('b', this.root, 'b', 'b')
1482
        this.tt.new_file('c', this.root, 'c', 'c')
1483
        this.tt.new_file('d', this.root, 'd2', 'd')
1484
        this.tt.new_file('e', this.root, 'e2', 'e')
1485
        this.tt.new_file('f', this.root, 'f', 'f')
1534.7.96 by Aaron Bentley
Tested with BASE as directory
1486
        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
1487
        this.tt.new_file('h', this.root, '1\n2\n3\n4\n', 'h')
1534.7.99 by Aaron Bentley
Handle non-existent BASE properly
1488
        this.tt.new_file('i', this.root, '1\n2\n3\n4\n', 'i')
1534.7.93 by Aaron Bentley
Added text merge test
1489
        this.tt.apply()
3008.1.11 by Michael Hudson
restore the default behaviour of Merge3Merger.__init__().
1490
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
3008.1.6 by Michael Hudson
chop up Merge3Merger.__init__ into pieces
1491
1534.7.95 by Aaron Bentley
Added more text merge tests
1492
        # textual merge
1534.7.93 by Aaron Bentley
Added text merge test
1493
        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
1494
        # three-way text conflict
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1495
        self.assertEqual(this.wt.get_file('b').read(),
1534.7.95 by Aaron Bentley
Added more text merge tests
1496
                         conflict_text('b', 'b2'))
1497
        # OTHER wins
1498
        self.assertEqual(this.wt.get_file('c').read(), 'c2')
1499
        # THIS wins
1500
        self.assertEqual(this.wt.get_file('d').read(), 'd2')
1501
        # Ambigious clean merge
1502
        self.assertEqual(this.wt.get_file('e').read(), 'e2')
1503
        # No change
1504
        self.assertEqual(this.wt.get_file('f').read(), 'f')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1505
        # Correct correct results when THIS == OTHER
1534.7.96 by Aaron Bentley
Tested with BASE as directory
1506
        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
1507
        # Text conflict when THIS & OTHER are text and BASE is dir
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1508
        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
1509
                         conflict_text('1\n2\n3\n4\n', 'h\ni\nj\nk\n'))
1510
        self.assertEqual(this.wt.get_file_byname('h.THIS').read(),
1511
                         '1\n2\n3\n4\n')
1512
        self.assertEqual(this.wt.get_file_byname('h.OTHER').read(),
1513
                         'h\ni\nj\nk\n')
1514
        self.assertEqual(file_kind(this.wt.abspath('h.BASE')), 'directory')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1515
        self.assertEqual(this.wt.get_file('i').read(),
1534.7.99 by Aaron Bentley
Handle non-existent BASE properly
1516
                         conflict_text('1\n2\n3\n4\n', 'h\ni\nj\nk\n'))
1517
        self.assertEqual(this.wt.get_file_byname('i.THIS').read(),
1518
                         '1\n2\n3\n4\n')
1519
        self.assertEqual(this.wt.get_file_byname('i.OTHER').read(),
1520
                         'h\ni\nj\nk\n')
1521
        self.assertEqual(os.path.exists(this.wt.abspath('i.BASE')), False)
1534.7.192 by Aaron Bentley
Record hashes produced by merges
1522
        modified = ['a', 'b', 'c', 'h', 'i']
1523
        merge_modified = this.wt.merge_modified()
1524
        self.assertSubset(merge_modified, modified)
1525
        self.assertEqual(len(merge_modified), len(modified))
1526
        file(this.wt.id2abspath('a'), 'wb').write('booga')
1527
        modified.pop(0)
1528
        merge_modified = this.wt.merge_modified()
1529
        self.assertSubset(merge_modified, modified)
1530
        self.assertEqual(len(merge_modified), len(modified))
1558.12.10 by Aaron Bentley
Be robust when merge_hash file_id not in inventory
1531
        this.wt.remove('b')
2796.1.4 by Aaron Bentley
Fix up various test cases
1532
        this.wt.revert()
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
1533
1534
    def test_file_merge(self):
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
1535
        self.requireFeature(SymlinkFeature)
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
1536
        root_id = generate_ids.gen_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1537
        base = TransformGroup("BASE", root_id)
1538
        this = TransformGroup("THIS", root_id)
1539
        other = TransformGroup("OTHER", root_id)
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
1540
        for tg in this, base, other:
1541
            tg.tt.new_directory('a', tg.root, 'a')
1542
            tg.tt.new_symlink('b', tg.root, 'b', 'b')
1543
            tg.tt.new_file('c', tg.root, 'c', 'c')
1544
            tg.tt.new_symlink('d', tg.root, tg.name, 'd')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1545
        targets = ((base, 'base-e', 'base-f', None, None),
1546
                   (this, 'other-e', 'this-f', 'other-g', 'this-h'),
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
1547
                   (other, 'other-e', None, 'other-g', 'other-h'))
1548
        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
1549
            for link, target in (('e', e_target), ('f', f_target),
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
1550
                                 ('g', g_target), ('h', h_target)):
1551
                if target is not None:
1552
                    tg.tt.new_symlink(link, tg.root, target, link)
1534.7.102 by Aaron Bentley
Deleted old pre-conflict contents
1553
1554
        for tg in this, base, other:
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
1555
            tg.tt.apply()
3008.1.11 by Michael Hudson
restore the default behaviour of Merge3Merger.__init__().
1556
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
1557
        self.assertIs(os.path.isdir(this.wt.abspath('a')), True)
1558
        self.assertIs(os.path.islink(this.wt.abspath('b')), True)
1559
        self.assertIs(os.path.isfile(this.wt.abspath('c')), True)
1560
        for suffix in ('THIS', 'BASE', 'OTHER'):
1561
            self.assertEqual(os.readlink(this.wt.abspath('d.'+suffix)), suffix)
1534.7.102 by Aaron Bentley
Deleted old pre-conflict contents
1562
        self.assertIs(os.path.lexists(this.wt.abspath('d')), False)
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
1563
        self.assertEqual(this.wt.id2path('d'), 'd.OTHER')
1564
        self.assertEqual(this.wt.id2path('f'), 'f.THIS')
1534.7.102 by Aaron Bentley
Deleted old pre-conflict contents
1565
        self.assertEqual(os.readlink(this.wt.abspath('e')), 'other-e')
1566
        self.assertIs(os.path.lexists(this.wt.abspath('e.THIS')), False)
1567
        self.assertIs(os.path.lexists(this.wt.abspath('e.OTHER')), False)
1568
        self.assertIs(os.path.lexists(this.wt.abspath('e.BASE')), False)
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
1569
        self.assertIs(os.path.lexists(this.wt.abspath('g')), True)
1570
        self.assertIs(os.path.lexists(this.wt.abspath('g.BASE')), False)
1571
        self.assertIs(os.path.lexists(this.wt.abspath('h')), False)
1572
        self.assertIs(os.path.lexists(this.wt.abspath('h.BASE')), False)
1573
        self.assertIs(os.path.lexists(this.wt.abspath('h.THIS')), True)
1574
        self.assertIs(os.path.lexists(this.wt.abspath('h.OTHER')), True)
1534.7.105 by Aaron Bentley
Got merge with rename working
1575
1576
    def test_filename_merge(self):
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
1577
        root_id = generate_ids.gen_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1578
        base = TransformGroup("BASE", root_id)
1579
        this = TransformGroup("THIS", root_id)
1580
        other = TransformGroup("OTHER", root_id)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1581
        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
1582
                                   for t in [base, this, other]]
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1583
        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
1584
                                   for t in [base, this, other]]
1585
        base.tt.new_directory('c', base_a, 'c')
1586
        this.tt.new_directory('c1', this_a, 'c')
1587
        other.tt.new_directory('c', other_b, 'c')
1588
1589
        base.tt.new_directory('d', base_a, 'd')
1590
        this.tt.new_directory('d1', this_b, 'd')
1591
        other.tt.new_directory('d', other_a, 'd')
1592
1593
        base.tt.new_directory('e', base_a, 'e')
1594
        this.tt.new_directory('e', this_a, 'e')
1595
        other.tt.new_directory('e1', other_b, 'e')
1596
1597
        base.tt.new_directory('f', base_a, 'f')
1598
        this.tt.new_directory('f1', this_b, 'f')
1599
        other.tt.new_directory('f1', other_b, 'f')
1600
1601
        for tg in [this, base, other]:
1602
            tg.tt.apply()
3008.1.11 by Michael Hudson
restore the default behaviour of Merge3Merger.__init__().
1603
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1534.7.176 by abentley
Fixed up tests for Windows
1604
        self.assertEqual(this.wt.id2path('c'), pathjoin('b/c1'))
1605
        self.assertEqual(this.wt.id2path('d'), pathjoin('b/d1'))
1606
        self.assertEqual(this.wt.id2path('e'), pathjoin('b/e1'))
1607
        self.assertEqual(this.wt.id2path('f'), pathjoin('b/f1'))
1534.7.105 by Aaron Bentley
Got merge with rename working
1608
1609
    def test_filename_merge_conflicts(self):
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
1610
        root_id = generate_ids.gen_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
1611
        base = TransformGroup("BASE", root_id)
1612
        this = TransformGroup("THIS", root_id)
1613
        other = TransformGroup("OTHER", root_id)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1614
        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
1615
                                   for t in [base, this, other]]
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1616
        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
1617
                                   for t in [base, this, other]]
1618
1619
        base.tt.new_file('g', base_a, 'g', 'g')
1620
        other.tt.new_file('g1', other_b, 'g1', 'g')
1621
1622
        base.tt.new_file('h', base_a, 'h', 'h')
1623
        this.tt.new_file('h1', this_b, 'h1', 'h')
1624
1625
        base.tt.new_file('i', base.root, 'i', 'i')
1534.7.153 by Aaron Bentley
Handled test cases involving symlinks
1626
        other.tt.new_directory('i1', this_b, 'i')
1534.7.105 by Aaron Bentley
Got merge with rename working
1627
1628
        for tg in [this, base, other]:
1629
            tg.tt.apply()
3008.1.11 by Michael Hudson
restore the default behaviour of Merge3Merger.__init__().
1630
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1534.7.105 by Aaron Bentley
Got merge with rename working
1631
1534.7.176 by abentley
Fixed up tests for Windows
1632
        self.assertEqual(this.wt.id2path('g'), pathjoin('b/g1.OTHER'))
1534.7.105 by Aaron Bentley
Got merge with rename working
1633
        self.assertIs(os.path.lexists(this.wt.abspath('b/g1.BASE')), True)
1634
        self.assertIs(os.path.lexists(this.wt.abspath('b/g1.THIS')), False)
1534.7.176 by abentley
Fixed up tests for Windows
1635
        self.assertEqual(this.wt.id2path('h'), pathjoin('b/h1.THIS'))
1534.7.105 by Aaron Bentley
Got merge with rename working
1636
        self.assertIs(os.path.lexists(this.wt.abspath('b/h1.BASE')), True)
1637
        self.assertIs(os.path.lexists(this.wt.abspath('b/h1.OTHER')), False)
1534.7.176 by abentley
Fixed up tests for Windows
1638
        self.assertEqual(this.wt.id2path('i'), pathjoin('b/i1.OTHER'))
1534.7.183 by Aaron Bentley
Fixed build_tree with symlinks
1639
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
1640
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1641
class TestBuildTree(tests.TestCaseWithTransport):
1642
3006.2.2 by Alexander Belchenko
tests added.
1643
    def test_build_tree_with_symlinks(self):
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
1644
        self.requireFeature(SymlinkFeature)
1534.7.183 by Aaron Bentley
Fixed build_tree with symlinks
1645
        os.mkdir('a')
1646
        a = BzrDir.create_standalone_workingtree('a')
1647
        os.mkdir('a/foo')
1648
        file('a/foo/bar', 'wb').write('contents')
1649
        os.symlink('a/foo/bar', 'a/foo/baz')
1650
        a.add(['foo', 'foo/bar', 'foo/baz'])
1651
        a.commit('initial commit')
1652
        b = BzrDir.create_standalone_workingtree('b')
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
1653
        basis = a.basis_tree()
1654
        basis.lock_read()
1655
        self.addCleanup(basis.unlock)
1656
        build_tree(basis, b)
1534.7.183 by Aaron Bentley
Fixed build_tree with symlinks
1657
        self.assertIs(os.path.isdir('b/foo'), True)
1658
        self.assertEqual(file('b/foo/bar', 'rb').read(), "contents")
1659
        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
1660
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
1661
    def test_build_with_references(self):
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
1662
        tree = self.make_branch_and_tree('source',
1663
            format='dirstate-with-subtree')
1664
        subtree = self.make_branch_and_tree('source/subtree',
1665
            format='dirstate-with-subtree')
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
1666
        tree.add_reference(subtree)
1667
        tree.commit('a revision')
1668
        tree.branch.create_checkout('target')
1669
        self.failUnlessExists('target')
1670
        self.failUnlessExists('target/subtree')
1671
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1672
    def test_file_conflict_handling(self):
1673
        """Ensure that when building trees, conflict handling is done"""
1674
        source = self.make_branch_and_tree('source')
1675
        target = self.make_branch_and_tree('target')
1676
        self.build_tree(['source/file', 'target/file'])
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1677
        source.add('file', 'new-file')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1678
        source.commit('added file')
1679
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1680
        self.assertEqual([DuplicateEntry('Moved existing file to',
1681
                          'file.moved', 'file', None, 'new-file')],
1682
                         target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1683
        target2 = self.make_branch_and_tree('target2')
1684
        target_file = file('target2/file', 'wb')
1685
        try:
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1686
            source_file = file('source/file', 'rb')
1687
            try:
1688
                target_file.write(source_file.read())
1689
            finally:
1690
                source_file.close()
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1691
        finally:
1692
            target_file.close()
1693
        build_tree(source.basis_tree(), target2)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1694
        self.assertEqual([], target2.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1695
1696
    def test_symlink_conflict_handling(self):
1697
        """Ensure that when building trees, conflict handling is done"""
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
1698
        self.requireFeature(SymlinkFeature)
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1699
        source = self.make_branch_and_tree('source')
1700
        os.symlink('foo', 'source/symlink')
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1701
        source.add('symlink', 'new-symlink')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1702
        source.commit('added file')
1703
        target = self.make_branch_and_tree('target')
1704
        os.symlink('bar', 'target/symlink')
1705
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1706
        self.assertEqual([DuplicateEntry('Moved existing file to',
1707
            'symlink.moved', 'symlink', None, 'new-symlink')],
1708
            target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1709
        target = self.make_branch_and_tree('target2')
1710
        os.symlink('foo', 'target2/symlink')
1711
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1712
        self.assertEqual([], target.conflicts())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1713
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1714
    def test_directory_conflict_handling(self):
1715
        """Ensure that when building trees, conflict handling is done"""
1716
        source = self.make_branch_and_tree('source')
1717
        target = self.make_branch_and_tree('target')
1718
        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
1719
        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
1720
        source.commit('added file')
1721
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1722
        self.assertEqual([], target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1723
        self.failUnlessExists('target/dir1/file')
1724
1725
        # Ensure contents are merged
1726
        target = self.make_branch_and_tree('target2')
1727
        self.build_tree(['target2/dir1/', 'target2/dir1/file2'])
1728
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1729
        self.assertEqual([], target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1730
        self.failUnlessExists('target2/dir1/file2')
1731
        self.failUnlessExists('target2/dir1/file')
1732
1733
        # 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
1734
        target = self.make_branch_and_tree('target3')
1735
        self.make_branch('target3/dir1')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1736
        self.build_tree(['target3/dir1/file2'])
1737
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1738
        self.failIfExists('target3/dir1/file')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1739
        self.failUnlessExists('target3/dir1/file2')
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1740
        self.failUnlessExists('target3/dir1.diverted/file')
1741
        self.assertEqual([DuplicateEntry('Diverted to',
1742
            'dir1.diverted', 'dir1', 'new-dir1', None)],
1743
            target.conflicts())
1744
1745
        target = self.make_branch_and_tree('target4')
1746
        self.build_tree(['target4/dir1/'])
1747
        self.make_branch('target4/dir1/file')
1748
        build_tree(source.basis_tree(), target)
1749
        self.failUnlessExists('target4/dir1/file')
1750
        self.assertEqual('directory', file_kind('target4/dir1/file'))
1751
        self.failUnlessExists('target4/dir1/file.diverted')
1752
        self.assertEqual([DuplicateEntry('Diverted to',
1753
            'dir1/file.diverted', 'dir1/file', 'new-file', None)],
1754
            target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1755
1756
    def test_mixed_conflict_handling(self):
1757
        """Ensure that when building trees, conflict handling is done"""
1758
        source = self.make_branch_and_tree('source')
1759
        target = self.make_branch_and_tree('target')
1760
        self.build_tree(['source/name', 'target/name/'])
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1761
        source.add('name', 'new-name')
1762
        source.commit('added file')
1763
        build_tree(source.basis_tree(), target)
1764
        self.assertEqual([DuplicateEntry('Moved existing file to',
1765
            'name.moved', 'name', None, 'new-name')], target.conflicts())
1766
1767
    def test_raises_in_populated(self):
1768
        source = self.make_branch_and_tree('source')
1769
        self.build_tree(['source/name'])
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1770
        source.add('name')
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1771
        source.commit('added name')
1772
        target = self.make_branch_and_tree('target')
1773
        self.build_tree(['target/name'])
1774
        target.add('name')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1775
        self.assertRaises(errors.WorkingTreeAlreadyPopulated,
2090.2.1 by Martin Pool
Fix some code which relies on assertions and breaks under python -O
1776
            build_tree, source.basis_tree(), target)
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1777
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1778
    def test_build_tree_rename_count(self):
1779
        source = self.make_branch_and_tree('source')
1780
        self.build_tree(['source/file1', 'source/dir1/'])
1781
        source.add(['file1', 'dir1'])
1782
        source.commit('add1')
1783
        target1 = self.make_branch_and_tree('target1')
2502.1.6 by Aaron Bentley
Update from review comments
1784
        transform_result = build_tree(source.basis_tree(), target1)
1785
        self.assertEqual(2, transform_result.rename_count)
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1786
1787
        self.build_tree(['source/dir1/file2'])
1788
        source.add(['dir1/file2'])
1789
        source.commit('add3')
1790
        target2 = self.make_branch_and_tree('target2')
2502.1.6 by Aaron Bentley
Update from review comments
1791
        transform_result = build_tree(source.basis_tree(), target2)
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1792
        # children of non-root directories should not be renamed
2502.1.6 by Aaron Bentley
Update from review comments
1793
        self.assertEqual(2, transform_result.rename_count)
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
1794
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
1795
    def create_ab_tree(self):
1796
        """Create a committed test tree with two files"""
1797
        source = self.make_branch_and_tree('source')
1798
        self.build_tree_contents([('source/file1', 'A')])
1799
        self.build_tree_contents([('source/file2', 'B')])
1800
        source.add(['file1', 'file2'], ['file1-id', 'file2-id'])
1801
        source.commit('commit files')
1802
        source.lock_write()
1803
        self.addCleanup(source.unlock)
1804
        return source
1805
3123.5.1 by Aaron Bentley
Make build-tree able to use an additional 'accelerator' tree
1806
    def test_build_tree_accelerator_tree(self):
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
1807
        source = self.create_ab_tree()
3123.5.1 by Aaron Bentley
Make build-tree able to use an additional 'accelerator' tree
1808
        self.build_tree_contents([('source/file2', 'C')])
1809
        calls = []
1810
        real_source_get_file = source.get_file
1811
        def get_file(file_id, path=None):
1812
            calls.append(file_id)
1813
            return real_source_get_file(file_id, path)
1814
        source.get_file = get_file
1815
        target = self.make_branch_and_tree('target')
3123.5.19 by Aaron Bentley
Ensure content is exactly the same, when accelerator used
1816
        revision_tree = source.basis_tree()
1817
        revision_tree.lock_read()
1818
        self.addCleanup(revision_tree.unlock)
1819
        build_tree(revision_tree, target, source)
3123.5.1 by Aaron Bentley
Make build-tree able to use an additional 'accelerator' tree
1820
        self.assertEqual(['file1-id'], calls)
3123.5.19 by Aaron Bentley
Ensure content is exactly the same, when accelerator used
1821
        target.lock_read()
1822
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1823
        self.assertEqual([], list(target.iter_changes(revision_tree)))
3123.5.1 by Aaron Bentley
Make build-tree able to use an additional 'accelerator' tree
1824
3123.5.4 by Aaron Bentley
Use an accelerator tree when branching, handle no-such-id correctly
1825
    def test_build_tree_accelerator_tree_missing_file(self):
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
1826
        source = self.create_ab_tree()
3123.5.4 by Aaron Bentley
Use an accelerator tree when branching, handle no-such-id correctly
1827
        os.unlink('source/file1')
1828
        source.remove(['file2'])
1829
        target = self.make_branch_and_tree('target')
3123.5.19 by Aaron Bentley
Ensure content is exactly the same, when accelerator used
1830
        revision_tree = source.basis_tree()
1831
        revision_tree.lock_read()
1832
        self.addCleanup(revision_tree.unlock)
1833
        build_tree(revision_tree, target, source)
1834
        target.lock_read()
1835
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1836
        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
1837
3123.5.16 by Aaron Bentley
Test handling of conversion to non-file
1838
    def test_build_tree_accelerator_wrong_kind(self):
3146.4.8 by Aaron Bentley
Add missing symlink requirement
1839
        self.requireFeature(SymlinkFeature)
3123.5.16 by Aaron Bentley
Test handling of conversion to non-file
1840
        source = self.make_branch_and_tree('source')
1841
        self.build_tree_contents([('source/file1', '')])
1842
        self.build_tree_contents([('source/file2', '')])
1843
        source.add(['file1', 'file2'], ['file1-id', 'file2-id'])
1844
        source.commit('commit files')
1845
        os.unlink('source/file2')
1846
        self.build_tree_contents([('source/file2/', 'C')])
1847
        os.unlink('source/file1')
1848
        os.symlink('file2', 'source/file1')
1849
        calls = []
1850
        real_source_get_file = source.get_file
1851
        def get_file(file_id, path=None):
1852
            calls.append(file_id)
1853
            return real_source_get_file(file_id, path)
1854
        source.get_file = get_file
1855
        target = self.make_branch_and_tree('target')
3123.5.19 by Aaron Bentley
Ensure content is exactly the same, when accelerator used
1856
        revision_tree = source.basis_tree()
1857
        revision_tree.lock_read()
1858
        self.addCleanup(revision_tree.unlock)
1859
        build_tree(revision_tree, target, source)
3123.5.16 by Aaron Bentley
Test handling of conversion to non-file
1860
        self.assertEqual([], calls)
3123.5.19 by Aaron Bentley
Ensure content is exactly the same, when accelerator used
1861
        target.lock_read()
1862
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1863
        self.assertEqual([], list(target.iter_changes(revision_tree)))
3123.5.16 by Aaron Bentley
Test handling of conversion to non-file
1864
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
1865
    def test_build_tree_hardlink(self):
1866
        self.requireFeature(HardlinkFeature)
1867
        source = self.create_ab_tree()
1868
        target = self.make_branch_and_tree('target')
1869
        revision_tree = source.basis_tree()
1870
        revision_tree.lock_read()
1871
        self.addCleanup(revision_tree.unlock)
1872
        build_tree(revision_tree, target, source, hardlink=True)
1873
        target.lock_read()
1874
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1875
        self.assertEqual([], list(target.iter_changes(revision_tree)))
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
1876
        source_stat = os.stat('source/file1')
1877
        target_stat = os.stat('target/file1')
1878
        self.assertEqual(source_stat, target_stat)
1879
1880
        # Explicitly disallowing hardlinks should prevent them.
1881
        target2 = self.make_branch_and_tree('target2')
1882
        build_tree(revision_tree, target2, source, hardlink=False)
1883
        target2.lock_read()
1884
        self.addCleanup(target2.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1885
        self.assertEqual([], list(target2.iter_changes(revision_tree)))
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
1886
        source_stat = os.stat('source/file1')
1887
        target2_stat = os.stat('target2/file1')
1888
        self.assertNotEqual(source_stat, target2_stat)
1889
3137.1.1 by Aaron Bentley
Fix build_tree acceleration when file is moved in accelerator_tree
1890
    def test_build_tree_accelerator_tree_moved(self):
1891
        source = self.make_branch_and_tree('source')
1892
        self.build_tree_contents([('source/file1', 'A')])
1893
        source.add(['file1'], ['file1-id'])
1894
        source.commit('commit files')
1895
        source.rename_one('file1', 'file2')
1896
        source.lock_read()
1897
        self.addCleanup(source.unlock)
1898
        target = self.make_branch_and_tree('target')
1899
        revision_tree = source.basis_tree()
1900
        revision_tree.lock_read()
1901
        self.addCleanup(revision_tree.unlock)
1902
        build_tree(revision_tree, target, source)
1903
        target.lock_read()
1904
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1905
        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
1906
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
1907
    def test_build_tree_hardlinks_preserve_execute(self):
1908
        self.requireFeature(HardlinkFeature)
1909
        source = self.create_ab_tree()
1910
        tt = TreeTransform(source)
1911
        trans_id = tt.trans_id_tree_file_id('file1-id')
1912
        tt.set_executability(True, trans_id)
1913
        tt.apply()
1914
        self.assertTrue(source.is_executable('file1-id'))
1915
        target = self.make_branch_and_tree('target')
1916
        revision_tree = source.basis_tree()
1917
        revision_tree.lock_read()
1918
        self.addCleanup(revision_tree.unlock)
1919
        build_tree(revision_tree, target, source, hardlink=True)
1920
        target.lock_read()
1921
        self.addCleanup(target.unlock)
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
1922
        self.assertEqual([], list(target.iter_changes(revision_tree)))
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
1923
        self.assertTrue(source.is_executable('file1-id'))
1924
4826.1.5 by Andrew Bennetts
Add test that content filtered files are not hardlinked by build_tree.
1925
    def install_rot13_content_filter(self, pattern):
4985.2.1 by Vincent Ladeuil
Deploy addAttrCleanup on the whole test suite.
1926
        # We could use
1927
        # self.addCleanup(filters._reset_registry, filters._reset_registry())
1928
        # below, but that looks a bit... hard to read even if it's exactly
1929
        # the same thing.
4826.1.5 by Andrew Bennetts
Add test that content filtered files are not hardlinked by build_tree.
1930
        original_registry = filters._reset_registry()
1931
        def restore_registry():
1932
            filters._reset_registry(original_registry)
1933
        self.addCleanup(restore_registry)
1934
        def rot13(chunks, context=None):
1935
            return [''.join(chunks).encode('rot13')]
1936
        rot13filter = filters.ContentFilter(rot13, rot13)
1937
        filters.register_filter_stack_map('rot13', {'yes': [rot13filter]}.get)
1938
        os.mkdir(self.test_home_dir + '/.bazaar')
1939
        rules_filename = self.test_home_dir + '/.bazaar/rules'
4826.1.8 by Andrew Bennetts
Tweaks suggested by John.
1940
        f = open(rules_filename, 'wb')
4826.1.5 by Andrew Bennetts
Add test that content filtered files are not hardlinked by build_tree.
1941
        f.write('[name %s]\nrot13=yes\n' % (pattern,))
1942
        f.close()
1943
        def uninstall_rules():
1944
            os.remove(rules_filename)
1945
            rules.reset_rules()
1946
        self.addCleanup(uninstall_rules)
1947
        rules.reset_rules()
1948
1949
    def test_build_tree_content_filtered_files_are_not_hardlinked(self):
1950
        """build_tree will not hardlink files that have content filtering rules
1951
        applied to them (but will still hardlink other files from the same tree
1952
        if it can).
1953
        """
1954
        self.requireFeature(HardlinkFeature)
1955
        self.install_rot13_content_filter('file1')
1956
        source = self.create_ab_tree()
1957
        target = self.make_branch_and_tree('target')
1958
        revision_tree = source.basis_tree()
1959
        revision_tree.lock_read()
1960
        self.addCleanup(revision_tree.unlock)
1961
        build_tree(revision_tree, target, source, hardlink=True)
1962
        target.lock_read()
1963
        self.addCleanup(target.unlock)
1964
        self.assertEqual([], list(target.iter_changes(revision_tree)))
1965
        source_stat = os.stat('source/file1')
1966
        target_stat = os.stat('target/file1')
1967
        self.assertNotEqual(source_stat, target_stat)
1968
        source_stat = os.stat('source/file2')
1969
        target_stat = os.stat('target/file2')
4826.1.8 by Andrew Bennetts
Tweaks suggested by John.
1970
        self.assertEqualStat(source_stat, target_stat)
4826.1.5 by Andrew Bennetts
Add test that content filtered files are not hardlinked by build_tree.
1971
3453.2.4 by Aaron Bentley
Disable fast-path when conflicts are encountered
1972
    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.
1973
        if (tests.CaseInsensitiveFilesystemFeature.available()
1974
            or tests.CaseInsCasePresFilenameFeature.available()):
4241.9.4 by Vincent Ladeuil
Fix test_case_insensitive_build_tree_inventory failure on OSX.
1975
            raise tests.UnavailableFeature('Fully case sensitive filesystem')
3453.2.4 by Aaron Bentley
Disable fast-path when conflicts are encountered
1976
        source = self.make_branch_and_tree('source')
1977
        self.build_tree(['source/file', 'source/FILE'])
1978
        source.add(['file', 'FILE'], ['lower-id', 'upper-id'])
1979
        source.commit('added files')
1980
        # Don't try this at home, kids!
1981
        # Force the tree to report that it is case insensitive
1982
        target = self.make_branch_and_tree('target')
1983
        target.case_sensitive = False
3453.2.6 by Aaron Bentley
Rename mutate_tree to delta_from_tree, add comment
1984
        build_tree(source.basis_tree(), target, source, delta_from_tree=True)
3453.2.4 by Aaron Bentley
Disable fast-path when conflicts are encountered
1985
        self.assertEqual('file.moved', target.id2path('lower-id'))
1986
        self.assertEqual('FILE', target.id2path('upper-id'))
1987
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1988
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
1989
class TestCommitTransform(tests.TestCaseWithTransport):
1990
1991
    def get_branch(self):
1992
        tree = self.make_branch_and_tree('tree')
1993
        tree.lock_write()
1994
        self.addCleanup(tree.unlock)
1995
        tree.commit('empty commit')
1996
        return tree.branch
1997
1998
    def get_branch_and_transform(self):
1999
        branch = self.get_branch()
2000
        tt = TransformPreview(branch.basis_tree())
2001
        self.addCleanup(tt.finalize)
2002
        return branch, tt
2003
2004
    def test_commit_wrong_basis(self):
2005
        branch = self.get_branch()
2006
        basis = branch.repository.revision_tree(
2007
            _mod_revision.NULL_REVISION)
2008
        tt = TransformPreview(basis)
2009
        self.addCleanup(tt.finalize)
4526.8.5 by Aaron Bentley
Updates from review.
2010
        e = self.assertRaises(ValueError, tt.commit, branch, '')
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2011
        self.assertEqual('TreeTransform not based on branch basis: null:',
2012
                         str(e))
2013
2014
    def test_empy_commit(self):
2015
        branch, tt = self.get_branch_and_transform()
2016
        rev = tt.commit(branch, 'my message')
2017
        self.assertEqual(2, branch.revno())
2018
        repo = branch.repository
2019
        self.assertEqual('my message', repo.get_revision(rev).message)
2020
2021
    def test_merge_parents(self):
2022
        branch, tt = self.get_branch_and_transform()
2023
        rev = tt.commit(branch, 'my message', ['rev1b', 'rev1c'])
2024
        self.assertEqual(['rev1b', 'rev1c'],
2025
                         branch.basis_tree().get_parent_ids()[1:])
2026
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2027
    def test_first_commit(self):
2028
        branch = self.make_branch('branch')
2029
        branch.lock_write()
2030
        self.addCleanup(branch.unlock)
2031
        tt = TransformPreview(branch.basis_tree())
4659.2.4 by Vincent Ladeuil
Cleanup remaining bzr-limbo-XXXXXX leaks in /tmp during selftest.
2032
        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.
2033
        tt.new_directory('', ROOT_PARENT, 'TREE_ROOT')
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2034
        rev = tt.commit(branch, 'my message')
2035
        self.assertEqual([], branch.basis_tree().get_parent_ids())
4526.8.5 by Aaron Bentley
Updates from review.
2036
        self.assertNotEqual(_mod_revision.NULL_REVISION,
2037
                            branch.last_revision())
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2038
4526.8.5 by Aaron Bentley
Updates from review.
2039
    def test_first_commit_with_merge_parents(self):
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2040
        branch = self.make_branch('branch')
2041
        branch.lock_write()
2042
        self.addCleanup(branch.unlock)
2043
        tt = TransformPreview(branch.basis_tree())
4659.2.4 by Vincent Ladeuil
Cleanup remaining bzr-limbo-XXXXXX leaks in /tmp during selftest.
2044
        self.addCleanup(tt.finalize)
4526.8.5 by Aaron Bentley
Updates from review.
2045
        e = self.assertRaises(ValueError, tt.commit, branch,
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2046
                          'my message', ['rev1b-id'])
4526.8.5 by Aaron Bentley
Updates from review.
2047
        self.assertEqual('Cannot supply merge parents for first commit.',
2048
                         str(e))
2049
        self.assertEqual(_mod_revision.NULL_REVISION, branch.last_revision())
4526.8.3 by Aaron Bentley
Clean up merge parent handling.
2050
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2051
    def test_add_files(self):
2052
        branch, tt = self.get_branch_and_transform()
2053
        tt.new_file('file', tt.root, 'contents', 'file-id')
2054
        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
2055
        if SymlinkFeature.available():
2056
            tt.new_symlink('symlink', trans_id, 'target', 'symlink-id')
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2057
        rev = tt.commit(branch, 'message')
2058
        tree = branch.basis_tree()
2059
        self.assertEqual('file', tree.id2path('file-id'))
2060
        self.assertEqual('contents', tree.get_file_text('file-id'))
2061
        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
2062
        if SymlinkFeature.available():
2063
            self.assertEqual('dir/symlink', tree.id2path('symlink-id'))
2064
            self.assertEqual('target', tree.get_symlink_target('symlink-id'))
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2065
4526.8.2 by Aaron Bentley
Proved strict commit handling.
2066
    def test_add_unversioned(self):
2067
        branch, tt = self.get_branch_and_transform()
2068
        tt.new_file('file', tt.root, 'contents')
2069
        self.assertRaises(errors.StrictCommitFailed, tt.commit, branch,
2070
                          'message', strict=True)
2071
2072
    def test_modify_strict(self):
2073
        branch, tt = self.get_branch_and_transform()
2074
        tt.new_file('file', tt.root, 'contents', 'file-id')
2075
        tt.commit(branch, 'message', strict=True)
2076
        tt = TransformPreview(branch.basis_tree())
4659.2.4 by Vincent Ladeuil
Cleanup remaining bzr-limbo-XXXXXX leaks in /tmp during selftest.
2077
        self.addCleanup(tt.finalize)
4526.8.2 by Aaron Bentley
Proved strict commit handling.
2078
        trans_id = tt.trans_id_file_id('file-id')
2079
        tt.delete_contents(trans_id)
2080
        tt.create_file('contents', trans_id)
2081
        tt.commit(branch, 'message', strict=True)
2082
4526.8.6 by Aaron Bentley
Check for malformed transforms before committing.
2083
    def test_commit_malformed(self):
2084
        """Committing a malformed transform should raise an exception.
2085
2086
        In this case, we are adding a file without adding its parent.
2087
        """
2088
        branch, tt = self.get_branch_and_transform()
2089
        parent_id = tt.trans_id_file_id('parent-id')
2090
        tt.new_file('file', parent_id, 'contents', 'file-id')
2091
        self.assertRaises(errors.MalformedTransform, tt.commit, branch,
2092
                          'message')
2093
4526.8.1 by Aaron Bentley
Support committing a TreeTransform to a branch.
2094
1534.10.28 by Aaron Bentley
Use numbered backup files
2095
class MockTransform(object):
2096
2097
    def has_named_child(self, by_parent, parent_id, name):
2098
        for child_id in by_parent[parent_id]:
2099
            if child_id == '0':
2100
                if name == "name~":
2101
                    return True
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
2102
            elif name == "name.~%s~" % child_id:
1534.10.28 by Aaron Bentley
Use numbered backup files
2103
                return True
2104
        return False
2105
2502.1.1 by Aaron Bentley
Ensure renames only root children are renamed when building trees
2106
1534.10.28 by Aaron Bentley
Use numbered backup files
2107
class MockEntry(object):
2108
    def __init__(self):
2109
        object.__init__(self)
2110
        self.name = "name"
2111
3063.1.1 by Alexander Belchenko
Catch OSError 17 (file exists) in final phase of tree transform and show filename to user (#111758).
2112
1534.10.28 by Aaron Bentley
Use numbered backup files
2113
class TestGetBackupName(TestCase):
2114
    def test_get_backup_name(self):
2115
        tt = MockTransform()
2116
        name = get_backup_name(MockEntry(), {'a':[]}, 'a', tt)
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
2117
        self.assertEqual(name, 'name.~1~')
2118
        name = get_backup_name(MockEntry(), {'a':['1']}, 'a', tt)
2119
        self.assertEqual(name, 'name.~2~')
1534.10.28 by Aaron Bentley
Use numbered backup files
2120
        name = get_backup_name(MockEntry(), {'a':['2']}, 'a', tt)
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
2121
        self.assertEqual(name, 'name.~1~')
1534.10.28 by Aaron Bentley
Use numbered backup files
2122
        name = get_backup_name(MockEntry(), {'a':['2'], 'b':[]}, 'b', tt)
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
2123
        self.assertEqual(name, 'name.~1~')
2124
        name = get_backup_name(MockEntry(), {'a':['1', '2', '3']}, 'a', tt)
2125
        self.assertEqual(name, 'name.~4~')
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2126
2127
2128
class TestFileMover(tests.TestCaseWithTransport):
2129
2130
    def test_file_mover(self):
2131
        self.build_tree(['a/', 'a/b', 'c/', 'c/d'])
2132
        mover = _FileMover()
2133
        mover.rename('a', 'q')
2134
        self.failUnlessExists('q')
2135
        self.failIfExists('a')
2733.2.12 by Aaron Bentley
Updates from review
2136
        self.failUnlessExists('q/b')
2137
        self.failUnlessExists('c')
2138
        self.failUnlessExists('c/d')
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2139
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2140
    def test_pre_delete_rollback(self):
2141
        self.build_tree(['a/'])
2142
        mover = _FileMover()
2143
        mover.pre_delete('a', 'q')
2144
        self.failUnlessExists('q')
2145
        self.failIfExists('a')
2146
        mover.rollback()
2147
        self.failIfExists('q')
2148
        self.failUnlessExists('a')
2149
2150
    def test_apply_deletions(self):
2733.2.12 by Aaron Bentley
Updates from review
2151
        self.build_tree(['a/', 'b/'])
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2152
        mover = _FileMover()
2153
        mover.pre_delete('a', 'q')
2733.2.12 by Aaron Bentley
Updates from review
2154
        mover.pre_delete('b', 'r')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2155
        self.failUnlessExists('q')
2733.2.12 by Aaron Bentley
Updates from review
2156
        self.failUnlessExists('r')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2157
        self.failIfExists('a')
2733.2.12 by Aaron Bentley
Updates from review
2158
        self.failIfExists('b')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2159
        mover.apply_deletions()
2160
        self.failIfExists('q')
2733.2.12 by Aaron Bentley
Updates from review
2161
        self.failIfExists('r')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2162
        self.failIfExists('a')
2733.2.12 by Aaron Bentley
Updates from review
2163
        self.failIfExists('b')
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
2164
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2165
    def test_file_mover_rollback(self):
2166
        self.build_tree(['a/', 'a/b', 'c/', 'c/d/', 'c/e/'])
2167
        mover = _FileMover()
2168
        mover.rename('c/d', 'c/f')
2169
        mover.rename('c/e', 'c/d')
2170
        try:
2171
            mover.rename('a', 'c')
3063.1.3 by Aaron Bentley
Update for Linux
2172
        except errors.FileExists, e:
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
2173
            mover.rollback()
2174
        self.failUnlessExists('a')
2175
        self.failUnlessExists('c/d')
2733.2.3 by Aaron Bentley
Test tranform rollback
2176
2177
2178
class Bogus(Exception):
2179
    pass
2180
2181
2182
class TestTransformRollback(tests.TestCaseWithTransport):
2183
2184
    class ExceptionFileMover(_FileMover):
2185
2733.2.4 by Aaron Bentley
Test transform rollback when renaming into place
2186
        def __init__(self, bad_source=None, bad_target=None):
2187
            _FileMover.__init__(self)
2188
            self.bad_source = bad_source
2189
            self.bad_target = bad_target
2190
2733.2.3 by Aaron Bentley
Test tranform rollback
2191
        def rename(self, source, target):
2733.2.4 by Aaron Bentley
Test transform rollback when renaming into place
2192
            if (self.bad_source is not None and
2193
                source.endswith(self.bad_source)):
2194
                raise Bogus
2195
            elif (self.bad_target is not None and
2196
                target.endswith(self.bad_target)):
2733.2.3 by Aaron Bentley
Test tranform rollback
2197
                raise Bogus
2198
            else:
2199
                _FileMover.rename(self, source, target)
2200
2201
    def test_rollback_rename(self):
2202
        tree = self.make_branch_and_tree('.')
2203
        self.build_tree(['a/', 'a/b'])
2204
        tt = TreeTransform(tree)
2205
        self.addCleanup(tt.finalize)
2206
        a_id = tt.trans_id_tree_path('a')
2207
        tt.adjust_path('c', tt.root, a_id)
2208
        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
2209
        self.assertRaises(Bogus, tt.apply,
2210
                          _mover=self.ExceptionFileMover(bad_source='a'))
2211
        self.failUnlessExists('a')
2212
        self.failUnlessExists('a/b')
2213
        tt.apply()
2214
        self.failUnlessExists('c')
2215
        self.failUnlessExists('c/d')
2216
2217
    def test_rollback_rename_into_place(self):
2218
        tree = self.make_branch_and_tree('.')
2219
        self.build_tree(['a/', 'a/b'])
2220
        tt = TreeTransform(tree)
2221
        self.addCleanup(tt.finalize)
2222
        a_id = tt.trans_id_tree_path('a')
2223
        tt.adjust_path('c', tt.root, a_id)
2224
        tt.adjust_path('d', a_id, tt.trans_id_tree_path('a/b'))
2225
        self.assertRaises(Bogus, tt.apply,
2226
                          _mover=self.ExceptionFileMover(bad_target='c/d'))
2227
        self.failUnlessExists('a')
2228
        self.failUnlessExists('a/b')
2229
        tt.apply()
2230
        self.failUnlessExists('c')
2231
        self.failUnlessExists('c/d')
2733.2.6 by Aaron Bentley
Make TreeTransform commits rollbackable
2232
2233
    def test_rollback_deletion(self):
2234
        tree = self.make_branch_and_tree('.')
2235
        self.build_tree(['a/', 'a/b'])
2236
        tt = TreeTransform(tree)
2237
        self.addCleanup(tt.finalize)
2238
        a_id = tt.trans_id_tree_path('a')
2239
        tt.delete_contents(a_id)
2240
        tt.adjust_path('d', tt.root, tt.trans_id_tree_path('a/b'))
2241
        self.assertRaises(Bogus, tt.apply,
2242
                          _mover=self.ExceptionFileMover(bad_target='d'))
2243
        self.failUnlessExists('a')
2244
        self.failUnlessExists('a/b')
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2245
1551.19.6 by Aaron Bentley
Revert doesn't crash restoring a file from a deleted directory
2246
    def test_resolve_no_parent(self):
2247
        wt = self.make_branch_and_tree('.')
2248
        tt = TreeTransform(wt)
2249
        self.addCleanup(tt.finalize)
2250
        parent = tt.trans_id_file_id('parent-id')
2251
        tt.new_file('file', parent, 'Contents')
2252
        resolve_conflicts(tt)
3008.1.13 by Michael Hudson
merge bzr.dev
2253
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2254
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2255
A_ENTRY = ('a-id', ('a', 'a'), True, (True, True),
2256
                  ('TREE_ROOT', 'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
2257
                  (False, False))
2258
ROOT_ENTRY = ('TREE_ROOT', ('', ''), False, (True, True), (None, None),
2259
              ('', ''), ('directory', 'directory'), (False, None))
2260
2261
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2262
class TestTransformPreview(tests.TestCaseWithTransport):
2263
2264
    def create_tree(self):
2265
        tree = self.make_branch_and_tree('.')
2266
        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.
2267
        tree.set_root_id('TREE_ROOT')
3008.2.1 by Aaron Bentley
Ensure conflict resolution works
2268
        tree.add('a', 'a-id')
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2269
        tree.commit('rev1', rev_id='rev1')
2270
        return tree.branch.repository.revision_tree('rev1')
2271
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2272
    def get_empty_preview(self):
2273
        repository = self.make_repository('repo')
2274
        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
2275
        preview = TransformPreview(tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2276
        self.addCleanup(preview.finalize)
3199.1.4 by Vincent Ladeuil
Fix 16 leaked tmp dirs. Probably indicates a lock handling problem with TransformPreview
2277
        return preview
2278
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2279
    def test_transform_preview(self):
2280
        revision_tree = self.create_tree()
2281
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2282
        self.addCleanup(preview.finalize)
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2283
2284
    def test_transform_preview_tree(self):
2285
        revision_tree = self.create_tree()
2286
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2287
        self.addCleanup(preview.finalize)
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2288
        preview.get_preview_tree()
2289
3008.1.5 by Michael Hudson
a more precise test
2290
    def test_transform_new_file(self):
2291
        revision_tree = self.create_tree()
2292
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2293
        self.addCleanup(preview.finalize)
3008.1.5 by Michael Hudson
a more precise test
2294
        preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
2295
        preview_tree = preview.get_preview_tree()
2296
        self.assertEqual(preview_tree.kind('file2-id'), 'file')
2297
        self.assertEqual(
2298
            preview_tree.get_file('file2-id').read(), 'content B\n')
2299
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2300
    def test_diff_preview_tree(self):
2301
        revision_tree = self.create_tree()
2302
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2303
        self.addCleanup(preview.finalize)
3008.1.4 by Michael Hudson
Merge test enhancements
2304
        preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
3008.1.1 by Aaron Bentley
Start work allowing previews of transforms
2305
        preview_tree = preview.get_preview_tree()
2306
        out = StringIO()
2307
        show_diff_trees(revision_tree, preview_tree, out)
3008.1.4 by Michael Hudson
Merge test enhancements
2308
        lines = out.getvalue().splitlines()
2309
        self.assertEqual(lines[0], "=== added file 'file2'")
2310
        # 3 lines of diff administrivia
2311
        self.assertEqual(lines[4], "+content B")
3008.2.1 by Aaron Bentley
Ensure conflict resolution works
2312
2313
    def test_transform_conflicts(self):
2314
        revision_tree = self.create_tree()
2315
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2316
        self.addCleanup(preview.finalize)
3008.2.1 by Aaron Bentley
Ensure conflict resolution works
2317
        preview.new_file('a', preview.root, 'content 2')
2318
        resolve_conflicts(preview)
2319
        trans_id = preview.trans_id_file_id('a-id')
2320
        self.assertEqual('a.moved', preview.final_name(trans_id))
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2321
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2322
    def get_tree_and_preview_tree(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2323
        revision_tree = self.create_tree()
2324
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2325
        self.addCleanup(preview.finalize)
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2326
        a_trans_id = preview.trans_id_file_id('a-id')
2327
        preview.delete_contents(a_trans_id)
2328
        preview.create_file('b content', a_trans_id)
2329
        preview_tree = preview.get_preview_tree()
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2330
        return revision_tree, preview_tree
2331
2332
    def test_iter_changes(self):
2333
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2334
        root = revision_tree.inventory.root.file_id
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2335
        self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
2336
                          (root, root), ('a', 'a'), ('file', 'file'),
2337
                          (False, False))],
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2338
                          list(preview_tree.iter_changes(revision_tree)))
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2339
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2340
    def test_include_unchanged_succeeds(self):
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2341
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2342
        changes = preview_tree.iter_changes(revision_tree,
2343
                                            include_unchanged=True)
2344
        root = revision_tree.inventory.root.file_id
2345
2346
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2347
2348
    def test_specific_files(self):
2349
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2350
        changes = preview_tree.iter_changes(revision_tree,
2351
                                            specific_files=[''])
2352
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2353
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2354
    def test_want_unversioned(self):
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2355
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3363.19.1 by Aaron Bentley
Make PreviewTree.iter_changes accept all options.
2356
        changes = preview_tree.iter_changes(revision_tree,
2357
                                            want_unversioned=True)
2358
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2359
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2360
    def test_ignore_extra_trees_no_specific_files(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2361
        # extra_trees is harmless without specific_files, so we'll silently
2362
        # accept it, even though we won't use it.
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2363
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2364
        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
2365
2366
    def test_ignore_require_versioned_no_specific_files(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2367
        # require_versioned is meaningless without specific_files.
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2368
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
2369
        preview_tree.iter_changes(revision_tree, require_versioned=False)
3008.1.31 by Aaron Bentley
Split PreviewTree._iter_changes parameter tests into smaller tests
2370
2371
    def test_ignore_pb(self):
3008.1.17 by Aaron Bentley
Test unused parameters of preview_tree._iter_changes
2372
        # 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
2373
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
2374
        preview_tree.iter_changes(revision_tree)
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2375
2376
    def test_kind(self):
2377
        revision_tree = self.create_tree()
2378
        preview = TransformPreview(revision_tree)
3199.1.5 by Vincent Ladeuil
Fix two more leaking tmp dirs, by reworking TransformPreview lock handling.
2379
        self.addCleanup(preview.finalize)
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2380
        preview.new_file('file', preview.root, 'contents', 'file-id')
2381
        preview.new_directory('directory', preview.root, 'dir-id')
2382
        preview_tree = preview.get_preview_tree()
2383
        self.assertEqual('file', preview_tree.kind('file-id'))
2384
        self.assertEqual('directory', preview_tree.kind('dir-id'))
2385
2386
    def test_get_file_mtime(self):
2387
        preview = self.get_empty_preview()
2388
        file_trans_id = preview.new_file('file', preview.root, 'contents',
2389
                                         'file-id')
2390
        limbo_path = preview._limbo_name(file_trans_id)
2391
        preview_tree = preview.get_preview_tree()
2392
        self.assertEqual(os.stat(limbo_path).st_mtime,
2393
                         preview_tree.get_file_mtime('file-id'))
2394
4635.1.1 by Aaron Bentley
Fix OSError with renamed files in PreviewTree.
2395
    def test_get_file_mtime_renamed(self):
2396
        work_tree = self.make_branch_and_tree('tree')
2397
        self.build_tree(['tree/file'])
2398
        work_tree.add('file', 'file-id')
2399
        preview = TransformPreview(work_tree)
2400
        self.addCleanup(preview.finalize)
2401
        file_trans_id = preview.trans_id_tree_file_id('file-id')
2402
        preview.adjust_path('renamed', preview.root, file_trans_id)
2403
        preview_tree = preview.get_preview_tree()
2404
        preview_mtime = preview_tree.get_file_mtime('file-id', 'renamed')
2405
        work_mtime = work_tree.get_file_mtime('file-id', 'file')
2406
3008.1.18 by Aaron Bentley
Get supported PreviewTree functionality under test
2407
    def test_get_file(self):
2408
        preview = self.get_empty_preview()
2409
        preview.new_file('file', preview.root, 'contents', 'file-id')
2410
        preview_tree = preview.get_preview_tree()
2411
        tree_file = preview_tree.get_file('file-id')
2412
        try:
2413
            self.assertEqual('contents', tree_file.read())
2414
        finally:
2415
            tree_file.close()
3228.1.2 by James Henstridge
Simplify test, and move it down to be next to the other _PreviewTree tests.
2416
2417
    def test_get_symlink_target(self):
2418
        self.requireFeature(SymlinkFeature)
2419
        preview = self.get_empty_preview()
2420
        preview.new_symlink('symlink', preview.root, 'target', 'symlink-id')
2421
        preview_tree = preview.get_preview_tree()
2422
        self.assertEqual('target',
2423
                         preview_tree.get_symlink_target('symlink-id'))
3363.2.18 by Aaron Bentley
Implement correct all_file_ids for PreviewTree
2424
2425
    def test_all_file_ids(self):
2426
        tree = self.make_branch_and_tree('tree')
2427
        self.build_tree(['tree/a', 'tree/b', 'tree/c'])
2428
        tree.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
2429
        preview = TransformPreview(tree)
2430
        self.addCleanup(preview.finalize)
2431
        preview.unversion_file(preview.trans_id_file_id('b-id'))
2432
        c_trans_id = preview.trans_id_file_id('c-id')
2433
        preview.unversion_file(c_trans_id)
2434
        preview.version_file('c-id', c_trans_id)
2435
        preview_tree = preview.get_preview_tree()
2436
        self.assertEqual(set(['a-id', 'c-id', tree.get_root_id()]),
2437
                         preview_tree.all_file_ids())
3363.2.19 by Aaron Bentley
Make PreviewTree.path2id correct
2438
2439
    def test_path2id_deleted_unchanged(self):
2440
        tree = self.make_branch_and_tree('tree')
2441
        self.build_tree(['tree/unchanged', 'tree/deleted'])
2442
        tree.add(['unchanged', 'deleted'], ['unchanged-id', 'deleted-id'])
2443
        preview = TransformPreview(tree)
2444
        self.addCleanup(preview.finalize)
2445
        preview.unversion_file(preview.trans_id_file_id('deleted-id'))
2446
        preview_tree = preview.get_preview_tree()
2447
        self.assertEqual('unchanged-id', preview_tree.path2id('unchanged'))
2448
        self.assertIs(None, preview_tree.path2id('deleted'))
2449
2450
    def test_path2id_created(self):
2451
        tree = self.make_branch_and_tree('tree')
2452
        self.build_tree(['tree/unchanged'])
2453
        tree.add(['unchanged'], ['unchanged-id'])
2454
        preview = TransformPreview(tree)
2455
        self.addCleanup(preview.finalize)
2456
        preview.new_file('new', preview.trans_id_file_id('unchanged-id'),
2457
            'contents', 'new-id')
2458
        preview_tree = preview.get_preview_tree()
2459
        self.assertEqual('new-id', preview_tree.path2id('unchanged/new'))
2460
2461
    def test_path2id_moved(self):
2462
        tree = self.make_branch_and_tree('tree')
2463
        self.build_tree(['tree/old_parent/', 'tree/old_parent/child'])
2464
        tree.add(['old_parent', 'old_parent/child'],
2465
                 ['old_parent-id', 'child-id'])
2466
        preview = TransformPreview(tree)
2467
        self.addCleanup(preview.finalize)
2468
        new_parent = preview.new_directory('new_parent', preview.root,
2469
                                           'new_parent-id')
2470
        preview.adjust_path('child', new_parent,
2471
                            preview.trans_id_file_id('child-id'))
2472
        preview_tree = preview.get_preview_tree()
2473
        self.assertIs(None, preview_tree.path2id('old_parent/child'))
2474
        self.assertEqual('child-id', preview_tree.path2id('new_parent/child'))
2475
2476
    def test_path2id_renamed_parent(self):
2477
        tree = self.make_branch_and_tree('tree')
2478
        self.build_tree(['tree/old_name/', 'tree/old_name/child'])
2479
        tree.add(['old_name', 'old_name/child'],
2480
                 ['parent-id', 'child-id'])
2481
        preview = TransformPreview(tree)
2482
        self.addCleanup(preview.finalize)
2483
        preview.adjust_path('new_name', preview.root,
2484
                            preview.trans_id_file_id('parent-id'))
2485
        preview_tree = preview.get_preview_tree()
2486
        self.assertIs(None, preview_tree.path2id('old_name/child'))
2487
        self.assertEqual('child-id', preview_tree.path2id('new_name/child'))
3363.2.21 by Aaron Bentley
Implement iter_entries_by_dir
2488
2489
    def assertMatchingIterEntries(self, tt, specific_file_ids=None):
2490
        preview_tree = tt.get_preview_tree()
2491
        preview_result = list(preview_tree.iter_entries_by_dir(
2492
                              specific_file_ids))
2493
        tree = tt._tree
2494
        tt.apply()
2495
        actual_result = list(tree.iter_entries_by_dir(specific_file_ids))
2496
        self.assertEqual(actual_result, preview_result)
2497
2498
    def test_iter_entries_by_dir_new(self):
2499
        tree = self.make_branch_and_tree('tree')
2500
        tt = TreeTransform(tree)
2501
        tt.new_file('new', tt.root, 'contents', 'new-id')
2502
        self.assertMatchingIterEntries(tt)
2503
2504
    def test_iter_entries_by_dir_deleted(self):
2505
        tree = self.make_branch_and_tree('tree')
2506
        self.build_tree(['tree/deleted'])
2507
        tree.add('deleted', 'deleted-id')
2508
        tt = TreeTransform(tree)
2509
        tt.delete_contents(tt.trans_id_file_id('deleted-id'))
2510
        self.assertMatchingIterEntries(tt)
2511
2512
    def test_iter_entries_by_dir_unversioned(self):
2513
        tree = self.make_branch_and_tree('tree')
2514
        self.build_tree(['tree/removed'])
2515
        tree.add('removed', 'removed-id')
2516
        tt = TreeTransform(tree)
2517
        tt.unversion_file(tt.trans_id_file_id('removed-id'))
2518
        self.assertMatchingIterEntries(tt)
2519
2520
    def test_iter_entries_by_dir_moved(self):
2521
        tree = self.make_branch_and_tree('tree')
2522
        self.build_tree(['tree/moved', 'tree/new_parent/'])
2523
        tree.add(['moved', 'new_parent'], ['moved-id', 'new_parent-id'])
2524
        tt = TreeTransform(tree)
2525
        tt.adjust_path('moved', tt.trans_id_file_id('new_parent-id'),
2526
                       tt.trans_id_file_id('moved-id'))
2527
        self.assertMatchingIterEntries(tt)
2528
2529
    def test_iter_entries_by_dir_specific_file_ids(self):
2530
        tree = self.make_branch_and_tree('tree')
2531
        tree.set_root_id('tree-root-id')
2532
        self.build_tree(['tree/parent/', 'tree/parent/child'])
2533
        tree.add(['parent', 'parent/child'], ['parent-id', 'child-id'])
2534
        tt = TreeTransform(tree)
2535
        self.assertMatchingIterEntries(tt, ['tree-root-id', 'child-id'])
3363.2.26 by Aaron Bentley
Get symlinks working
2536
2537
    def test_symlink_content_summary(self):
2538
        self.requireFeature(SymlinkFeature)
2539
        preview = self.get_empty_preview()
2540
        preview.new_symlink('path', preview.root, 'target', 'path-id')
2541
        summary = preview.get_preview_tree().path_content_summary('path')
2542
        self.assertEqual(('symlink', None, None, 'target'), summary)
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2543
2544
    def test_missing_content_summary(self):
2545
        preview = self.get_empty_preview()
2546
        summary = preview.get_preview_tree().path_content_summary('path')
2547
        self.assertEqual(('missing', None, None, None), summary)
2548
2549
    def test_deleted_content_summary(self):
2550
        tree = self.make_branch_and_tree('tree')
2551
        self.build_tree(['tree/path/'])
2552
        tree.add('path')
2553
        preview = TransformPreview(tree)
2554
        self.addCleanup(preview.finalize)
2555
        preview.delete_contents(preview.trans_id_tree_path('path'))
2556
        summary = preview.get_preview_tree().path_content_summary('path')
2557
        self.assertEqual(('missing', None, None, None), summary)
2558
3363.2.30 by Aaron Bentley
Improve execute bit testing
2559
    def test_file_content_summary_executable(self):
2560
        preview = self.get_empty_preview()
2561
        path_id = preview.new_file('path', preview.root, 'contents', 'path-id')
2562
        preview.set_executability(True, path_id)
2563
        summary = preview.get_preview_tree().path_content_summary('path')
2564
        self.assertEqual(4, len(summary))
2565
        self.assertEqual('file', summary[0])
2566
        # size must be known
2567
        self.assertEqual(len('contents'), summary[1])
2568
        # executable
2569
        self.assertEqual(True, summary[2])
3363.2.31 by Aaron Bentley
Tweak tests
2570
        # will not have hash (not cheap to determine)
2571
        self.assertIs(None, summary[3])
3363.2.30 by Aaron Bentley
Improve execute bit testing
2572
2573
    def test_change_executability(self):
2574
        tree = self.make_branch_and_tree('tree')
2575
        self.build_tree(['tree/path'])
2576
        tree.add('path')
2577
        preview = TransformPreview(tree)
2578
        self.addCleanup(preview.finalize)
2579
        path_id = preview.trans_id_tree_path('path')
2580
        preview.set_executability(True, path_id)
2581
        summary = preview.get_preview_tree().path_content_summary('path')
2582
        self.assertEqual(True, summary[2])
2583
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2584
    def test_file_content_summary_non_exec(self):
2585
        preview = self.get_empty_preview()
2586
        preview.new_file('path', preview.root, 'contents', 'path-id')
2587
        summary = preview.get_preview_tree().path_content_summary('path')
2588
        self.assertEqual(4, len(summary))
2589
        self.assertEqual('file', summary[0])
2590
        # size must be known
3363.2.30 by Aaron Bentley
Improve execute bit testing
2591
        self.assertEqual(len('contents'), summary[1])
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2592
        # not executable
4789.15.3 by John Arbash Meinel
PreviewTree now returns False for exec bit properly.
2593
        self.assertEqual(False, summary[2])
3363.2.31 by Aaron Bentley
Tweak tests
2594
        # will not have hash (not cheap to determine)
2595
        self.assertIs(None, summary[3])
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
2596
2597
    def test_dir_content_summary(self):
2598
        preview = self.get_empty_preview()
2599
        preview.new_directory('path', preview.root, 'path-id')
2600
        summary = preview.get_preview_tree().path_content_summary('path')
2601
        self.assertEqual(('directory', None, None, None), summary)
2602
2603
    def test_tree_content_summary(self):
2604
        preview = self.get_empty_preview()
2605
        path = preview.new_directory('path', preview.root, 'path-id')
2606
        preview.set_tree_reference('rev-1', path)
2607
        summary = preview.get_preview_tree().path_content_summary('path')
2608
        self.assertEqual(4, len(summary))
2609
        self.assertEqual('tree-reference', summary[0])
3363.2.33 by Aaron Bentley
Implement PreviewTree.annotate_iter
2610
2611
    def test_annotate(self):
2612
        tree = self.make_branch_and_tree('tree')
2613
        self.build_tree_contents([('tree/file', 'a\n')])
2614
        tree.add('file', 'file-id')
2615
        tree.commit('a', rev_id='one')
2616
        self.build_tree_contents([('tree/file', 'a\nb\n')])
2617
        preview = TransformPreview(tree)
2618
        self.addCleanup(preview.finalize)
2619
        file_trans_id = preview.trans_id_file_id('file-id')
2620
        preview.delete_contents(file_trans_id)
2621
        preview.create_file('a\nb\nc\n', file_trans_id)
2622
        preview_tree = preview.get_preview_tree()
2623
        expected = [
2624
            ('one', 'a\n'),
2625
            ('me:', 'b\n'),
2626
            ('me:', 'c\n'),
2627
        ]
2628
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2629
        self.assertEqual(expected, annotation)
2630
2631
    def test_annotate_missing(self):
2632
        preview = self.get_empty_preview()
2633
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2634
        preview_tree = preview.get_preview_tree()
2635
        expected = [
2636
            ('me:', 'a\n'),
2637
            ('me:', 'b\n'),
2638
            ('me:', 'c\n'),
2639
         ]
2640
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2641
        self.assertEqual(expected, annotation)
2642
3363.7.3 by Aaron Bentley
Add test that annotate correctly handles renames
2643
    def test_annotate_rename(self):
2644
        tree = self.make_branch_and_tree('tree')
2645
        self.build_tree_contents([('tree/file', 'a\n')])
2646
        tree.add('file', 'file-id')
2647
        tree.commit('a', rev_id='one')
2648
        preview = TransformPreview(tree)
2649
        self.addCleanup(preview.finalize)
2650
        file_trans_id = preview.trans_id_file_id('file-id')
2651
        preview.adjust_path('newname', preview.root, file_trans_id)
2652
        preview_tree = preview.get_preview_tree()
2653
        expected = [
2654
            ('one', 'a\n'),
2655
        ]
2656
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2657
        self.assertEqual(expected, annotation)
2658
3363.2.33 by Aaron Bentley
Implement PreviewTree.annotate_iter
2659
    def test_annotate_deleted(self):
2660
        tree = self.make_branch_and_tree('tree')
2661
        self.build_tree_contents([('tree/file', 'a\n')])
2662
        tree.add('file', 'file-id')
2663
        tree.commit('a', rev_id='one')
2664
        self.build_tree_contents([('tree/file', 'a\nb\n')])
2665
        preview = TransformPreview(tree)
2666
        self.addCleanup(preview.finalize)
2667
        file_trans_id = preview.trans_id_file_id('file-id')
2668
        preview.delete_contents(file_trans_id)
2669
        preview_tree = preview.get_preview_tree()
2670
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2671
        self.assertIs(None, annotation)
2672
3363.2.36 by Aaron Bentley
Fix PreviewTree.stored_kind
2673
    def test_stored_kind(self):
2674
        preview = self.get_empty_preview()
2675
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2676
        preview_tree = preview.get_preview_tree()
2677
        self.assertEqual('file', preview_tree.stored_kind('file-id'))
3363.2.37 by Aaron Bentley
Fix is_executable
2678
2679
    def test_is_executable(self):
2680
        preview = self.get_empty_preview()
2681
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2682
        preview.set_executability(True, preview.trans_id_file_id('file-id'))
2683
        preview_tree = preview.get_preview_tree()
2684
        self.assertEqual(True, preview_tree.is_executable('file-id'))
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2685
3571.1.1 by Aaron Bentley
Allow set/get of parent_ids in PreviewTree
2686
    def test_get_set_parent_ids(self):
2687
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2688
        self.assertEqual([], preview_tree.get_parent_ids())
2689
        preview_tree.set_parent_ids(['rev-1'])
2690
        self.assertEqual(['rev-1'], preview_tree.get_parent_ids())
2691
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2692
    def test_plan_file_merge(self):
2693
        work_a = self.make_branch_and_tree('wta')
2694
        self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
2695
        work_a.add('file', 'file-id')
3363.9.7 by Aaron Bentley
Fix up to use set_parent_ids
2696
        base_id = work_a.commit('base version')
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2697
        tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
2698
        preview = TransformPreview(work_a)
2699
        self.addCleanup(preview.finalize)
2700
        trans_id = preview.trans_id_file_id('file-id')
2701
        preview.delete_contents(trans_id)
2702
        preview.create_file('b\nc\nd\ne\n', trans_id)
2703
        self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
2704
        tree_a = preview.get_preview_tree()
3363.9.7 by Aaron Bentley
Fix up to use set_parent_ids
2705
        tree_a.set_parent_ids([base_id])
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2706
        self.assertEqual([
3363.9.5 by Aaron Bentley
Move killed-a from top to bottom
2707
            ('killed-a', 'a\n'),
3363.9.1 by Aaron Bentley
Implement plan_merge, refactoring various bits
2708
            ('killed-b', 'b\n'),
2709
            ('unchanged', 'c\n'),
2710
            ('unchanged', 'd\n'),
2711
            ('new-a', 'e\n'),
2712
            ('new-b', 'f\n'),
2713
        ], 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
2714
2715
    def test_plan_file_merge_revision_tree(self):
2716
        work_a = self.make_branch_and_tree('wta')
2717
        self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
2718
        work_a.add('file', 'file-id')
2719
        base_id = work_a.commit('base version')
2720
        tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
2721
        preview = TransformPreview(work_a.basis_tree())
2722
        self.addCleanup(preview.finalize)
2723
        trans_id = preview.trans_id_file_id('file-id')
2724
        preview.delete_contents(trans_id)
2725
        preview.create_file('b\nc\nd\ne\n', trans_id)
2726
        self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
2727
        tree_a = preview.get_preview_tree()
2728
        tree_a.set_parent_ids([base_id])
2729
        self.assertEqual([
2730
            ('killed-a', 'a\n'),
2731
            ('killed-b', 'b\n'),
2732
            ('unchanged', 'c\n'),
2733
            ('unchanged', 'd\n'),
2734
            ('new-a', 'e\n'),
2735
            ('new-b', 'f\n'),
2736
        ], list(tree_a.plan_file_merge('file-id', tree_b)))
3363.9.9 by Aaron Bentley
Implement walkdirs in terms of TreeTransform
2737
2738
    def test_walkdirs(self):
2739
        preview = self.get_empty_preview()
4634.57.3 by Aaron Bentley
Fix failing test.
2740
        root = preview.new_directory('', ROOT_PARENT, 'tree-root')
2741
        # FIXME: new_directory should mark root.
4634.122.6 by John Arbash Meinel
Fix a test that used 'adjust_path' to set the root.
2742
        preview.fixup_new_roots()
3363.9.9 by Aaron Bentley
Implement walkdirs in terms of TreeTransform
2743
        preview_tree = preview.get_preview_tree()
2744
        file_trans_id = preview.new_file('a', preview.root, 'contents',
2745
                                         'a-id')
2746
        expected = [(('', 'tree-root'),
2747
                    [('a', 'a', 'file', None, 'a-id', 'file')])]
2748
        self.assertEqual(expected, list(preview_tree.walkdirs()))
3363.13.2 by Aaron Bentley
Test specific cases for PreviewTree.extras
2749
2750
    def test_extras(self):
2751
        work_tree = self.make_branch_and_tree('tree')
2752
        self.build_tree(['tree/removed-file', 'tree/existing-file',
2753
                         'tree/not-removed-file'])
2754
        work_tree.add(['removed-file', 'not-removed-file'])
2755
        preview = TransformPreview(work_tree)
3363.13.3 by Aaron Bentley
Add cleanup
2756
        self.addCleanup(preview.finalize)
3363.13.2 by Aaron Bentley
Test specific cases for PreviewTree.extras
2757
        preview.new_file('new-file', preview.root, 'contents')
2758
        preview.new_file('new-versioned-file', preview.root, 'contents',
2759
                         'new-versioned-id')
2760
        tree = preview.get_preview_tree()
2761
        preview.unversion_file(preview.trans_id_tree_path('removed-file'))
2762
        self.assertEqual(set(['new-file', 'removed-file', 'existing-file']),
2763
                         set(tree.extras()))
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2764
3363.17.2 by Aaron Bentley
Add text checking
2765
    def test_merge_into_preview(self):
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2766
        work_tree = self.make_branch_and_tree('tree')
3363.17.2 by Aaron Bentley
Add text checking
2767
        self.build_tree_contents([('tree/file','b\n')])
2768
        work_tree.add('file', 'file-id')
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2769
        work_tree.commit('first commit')
2770
        child_tree = work_tree.bzrdir.sprout('child').open_workingtree()
3363.17.2 by Aaron Bentley
Add text checking
2771
        self.build_tree_contents([('child/file','b\nc\n')])
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2772
        child_tree.commit('child commit')
2773
        child_tree.lock_write()
2774
        self.addCleanup(child_tree.unlock)
2775
        work_tree.lock_write()
2776
        self.addCleanup(work_tree.unlock)
2777
        preview = TransformPreview(work_tree)
2778
        self.addCleanup(preview.finalize)
3363.17.6 by Aaron Bentley
Improve test scenario
2779
        file_trans_id = preview.trans_id_file_id('file-id')
2780
        preview.delete_contents(file_trans_id)
2781
        preview.create_file('a\nb\n', file_trans_id)
4634.57.2 by Aaron Bentley
Fix failing test.
2782
        preview_tree = preview.get_preview_tree()
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
2783
        merger = Merger.from_revision_ids(None, preview_tree,
3363.17.1 by Aaron Bentley
Avoid inventory for merge and transform code
2784
                                          child_tree.branch.last_revision(),
2785
                                          other_branch=child_tree.branch,
2786
                                          tree_branch=work_tree.branch)
2787
        merger.merge_type = Merge3Merger
2788
        tt = merger.make_merger().make_preview_transform()
3363.17.2 by Aaron Bentley
Add text checking
2789
        self.addCleanup(tt.finalize)
2790
        final_tree = tt.get_preview_tree()
2791
        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
2792
2793
    def test_merge_preview_into_workingtree(self):
2794
        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.
2795
        tree.set_root_id('TREE_ROOT')
3363.17.17 by Aaron Bentley
Start testing merging PreviewTree as OTHER
2796
        tt = TransformPreview(tree)
2797
        self.addCleanup(tt.finalize)
2798
        tt.new_file('name', tt.root, 'content', 'file-id')
2799
        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.
2800
        tree2.set_root_id('TREE_ROOT')
3363.17.17 by Aaron Bentley
Start testing merging PreviewTree as OTHER
2801
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
2802
                                         None, tree.basis_tree())
3363.17.17 by Aaron Bentley
Start testing merging PreviewTree as OTHER
2803
        merger.merge_type = Merge3Merger
2804
        merger.do_merge()
3363.17.18 by Aaron Bentley
Fix is_executable for PreviewTree
2805
3363.17.21 by Aaron Bentley
Conflicts are handled when merging from preview trees
2806
    def test_merge_preview_into_workingtree_handles_conflicts(self):
2807
        tree = self.make_branch_and_tree('tree')
2808
        self.build_tree_contents([('tree/foo', 'bar')])
2809
        tree.add('foo', 'foo-id')
2810
        tree.commit('foo')
2811
        tt = TransformPreview(tree)
2812
        self.addCleanup(tt.finalize)
2813
        trans_id = tt.trans_id_file_id('foo-id')
2814
        tt.delete_contents(trans_id)
2815
        tt.create_file('baz', trans_id)
2816
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
2817
        self.build_tree_contents([('tree2/foo', 'qux')])
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
2818
        pb = None
3363.17.21 by Aaron Bentley
Conflicts are handled when merging from preview trees
2819
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
2820
                                         pb, tree.basis_tree())
2821
        merger.merge_type = Merge3Merger
2822
        merger.do_merge()
2823
3363.17.18 by Aaron Bentley
Fix is_executable for PreviewTree
2824
    def test_is_executable(self):
2825
        tree = self.make_branch_and_tree('tree')
2826
        preview = TransformPreview(tree)
2827
        self.addCleanup(preview.finalize)
2828
        preview.new_file('foo', preview.root, 'bar', 'baz-id')
2829
        preview_tree = preview.get_preview_tree()
2830
        self.assertEqual(False, preview_tree.is_executable('baz-id',
2831
                                                           'tree/foo'))
2832
        self.assertEqual(False, preview_tree.is_executable('baz-id'))
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2833
4354.4.4 by Aaron Bentley
Simplify by using CommitBuilder directly
2834
    def test_commit_preview_tree(self):
2835
        tree = self.make_branch_and_tree('tree')
2836
        rev_id = tree.commit('rev1')
2837
        tree.branch.lock_write()
2838
        self.addCleanup(tree.branch.unlock)
2839
        tt = TransformPreview(tree)
2840
        tt.new_file('file', tt.root, 'contents', 'file_id')
2841
        self.addCleanup(tt.finalize)
2842
        preview = tt.get_preview_tree()
2843
        preview.set_parent_ids([rev_id])
2844
        builder = tree.branch.get_commit_builder([rev_id])
2845
        list(builder.record_iter_changes(preview, rev_id, tt.iter_changes()))
2846
        builder.finish_inventory()
2847
        rev2_id = builder.commit('rev2')
2848
        rev2_tree = tree.branch.repository.revision_tree(rev2_id)
2849
        self.assertEqual('contents', rev2_tree.get_file_text('file_id'))
2850
4634.79.1 by Aaron Bentley
TransformPreview uses ascii-only filenames.
2851
    def test_ascii_limbo_paths(self):
4634.79.2 by Aaron Bentley
Avoid runing test on non-unicode filesystems.
2852
        self.requireFeature(tests.UnicodeFilenameFeature)
4634.79.1 by Aaron Bentley
TransformPreview uses ascii-only filenames.
2853
        branch = self.make_branch('any')
2854
        tree = branch.repository.revision_tree(_mod_revision.NULL_REVISION)
2855
        tt = TransformPreview(tree)
4789.25.7 by John Arbash Meinel
We can run the executable tests.
2856
        self.addCleanup(tt.finalize)
4634.79.1 by Aaron Bentley
TransformPreview uses ascii-only filenames.
2857
        foo_id = tt.new_directory('', ROOT_PARENT)
2858
        bar_id = tt.new_file(u'\u1234bar', foo_id, 'contents')
2859
        limbo_path = tt._limbo_name(bar_id)
2860
        self.assertEqual(limbo_path.encode('ascii', 'replace'), limbo_path)
2861
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2862
0.13.13 by Aaron Bentley
Add direct test of serialization records
2863
class FakeSerializer(object):
2864
    """Serializer implementation that simply returns the input.
2865
2866
    The input is returned in the order used by pack.ContainerPushParser.
2867
    """
2868
    @staticmethod
2869
    def bytes_record(bytes, names):
2870
        return names, bytes
2871
2872
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2873
class TestSerializeTransform(tests.TestCaseWithTransport):
2874
0.13.22 by Aaron Bentley
More unicodeness for Shelf tests
2875
    _test_needs_features = [tests.UnicodeFilenameFeature]
2876
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
2877
    def get_preview(self, tree=None):
2878
        if tree is None:
2879
            tree = self.make_branch_and_tree('tree')
0.13.14 by Aaron Bentley
Add deserialization test, remove roundtrip test.
2880
        tt = TransformPreview(tree)
2881
        self.addCleanup(tt.finalize)
2882
        return tt
2883
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2884
    def assertSerializesTo(self, expected, tt):
2885
        records = list(tt.serialize(FakeSerializer()))
2886
        self.assertEqual(expected, records)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2887
0.13.13 by Aaron Bentley
Add direct test of serialization records
2888
    @staticmethod
2889
    def default_attribs():
2890
        return {
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2891
            '_id_number': 1,
0.13.13 by Aaron Bentley
Add direct test of serialization records
2892
            '_new_name': {},
2893
            '_new_parent': {},
2894
            '_new_executability': {},
2895
            '_new_id': {},
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2896
            '_tree_path_ids': {'': 'new-0'},
0.13.13 by Aaron Bentley
Add direct test of serialization records
2897
            '_removed_id': [],
2898
            '_removed_contents': [],
2899
            '_non_present_ids': {},
2900
            }
2901
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2902
    def make_records(self, attribs, contents):
2903
        records = [
2904
            (((('attribs'),),), bencode.bencode(attribs))]
2905
        records.extend([(((n, k),), c) for n, k, c in contents])
2906
        return records
2907
0.13.13 by Aaron Bentley
Add direct test of serialization records
2908
    def creation_records(self):
2909
        attribs = self.default_attribs()
2910
        attribs['_id_number'] = 3
2911
        attribs['_new_name'] = {
2912
            'new-1': u'foo\u1234'.encode('utf-8'), 'new-2': 'qux'}
2913
        attribs['_new_id'] = {'new-1': 'baz', 'new-2': 'quxx'}
2914
        attribs['_new_parent'] = {'new-1': 'new-0', 'new-2': 'new-0'}
2915
        attribs['_new_executability'] = {'new-1': 1}
2916
        contents = [
2917
            ('new-1', 'file', 'i 1\nbar\n'),
2918
            ('new-2', 'directory', ''),
2919
            ]
2920
        return self.make_records(attribs, contents)
2921
2922
    def test_serialize_creation(self):
0.13.14 by Aaron Bentley
Add deserialization test, remove roundtrip test.
2923
        tt = self.get_preview()
0.13.13 by Aaron Bentley
Add direct test of serialization records
2924
        tt.new_file(u'foo\u1234', tt.root, 'bar', 'baz', True)
2925
        tt.new_directory('qux', tt.root, 'quxx')
0.13.21 by Aaron Bentley
Use assertSerializesTo in more places
2926
        self.assertSerializesTo(self.creation_records(), tt)
0.13.13 by Aaron Bentley
Add direct test of serialization records
2927
0.13.14 by Aaron Bentley
Add deserialization test, remove roundtrip test.
2928
    def test_deserialize_creation(self):
2929
        tt = self.get_preview()
2930
        tt.deserialize(iter(self.creation_records()))
2931
        self.assertEqual(3, tt._id_number)
2932
        self.assertEqual({'new-1': u'foo\u1234',
2933
                          'new-2': 'qux'}, tt._new_name)
2934
        self.assertEqual({'new-1': 'baz', 'new-2': 'quxx'}, tt._new_id)
2935
        self.assertEqual({'new-1': tt.root, 'new-2': tt.root}, tt._new_parent)
2936
        self.assertEqual({'baz': 'new-1', 'quxx': 'new-2'}, tt._r_new_id)
2937
        self.assertEqual({'new-1': True}, tt._new_executability)
2938
        self.assertEqual({'new-1': 'file',
2939
                          'new-2': 'directory'}, tt._new_contents)
2940
        foo_limbo = open(tt._limbo_name('new-1'), 'rb')
2941
        try:
2942
            foo_content = foo_limbo.read()
2943
        finally:
2944
            foo_limbo.close()
2945
        self.assertEqual('bar', foo_content)
2946
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2947
    def symlink_creation_records(self):
2948
        attribs = self.default_attribs()
2949
        attribs['_id_number'] = 2
2950
        attribs['_new_name'] = {'new-1': u'foo\u1234'.encode('utf-8')}
2951
        attribs['_new_parent'] = {'new-1': 'new-0'}
2952
        contents = [('new-1', 'symlink', u'bar\u1234'.encode('utf-8'))]
2953
        return self.make_records(attribs, contents)
2954
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2955
    def test_serialize_symlink_creation(self):
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2956
        self.requireFeature(tests.SymlinkFeature)
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2957
        tt = self.get_preview()
0.13.16 by Aaron Bentley
Add unicode symlink targets to tests
2958
        tt.new_symlink(u'foo\u1234', tt.root, u'bar\u1234')
0.13.21 by Aaron Bentley
Use assertSerializesTo in more places
2959
        self.assertSerializesTo(self.symlink_creation_records(), tt)
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2960
2961
    def test_deserialize_symlink_creation(self):
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
2962
        self.requireFeature(tests.SymlinkFeature)
0.13.15 by Aaron Bentley
Convert symlink tests to avoid roundtripping
2963
        tt = self.get_preview()
2964
        tt.deserialize(iter(self.symlink_creation_records()))
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
2965
        abspath = tt._limbo_name('new-1')
4241.14.17 by Vincent Ladeuil
Add more tests for unicode symlinks to test_transform.
2966
        foo_content = osutils.readlink(abspath)
0.13.22 by Aaron Bentley
More unicodeness for Shelf tests
2967
        self.assertEqual(u'bar\u1234', foo_content)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2968
0.13.19 by Aaron Bentley
Clean up serialization tests
2969
    def make_destruction_preview(self):
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2970
        tree = self.make_branch_and_tree('.')
2971
        self.build_tree([u'foo\u1234', 'bar'])
2972
        tree.add([u'foo\u1234', 'bar'], ['foo-id', 'bar-id'])
0.13.19 by Aaron Bentley
Clean up serialization tests
2973
        return self.get_preview(tree)
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
2974
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2975
    def destruction_records(self):
2976
        attribs = self.default_attribs()
2977
        attribs['_id_number'] = 3
2978
        attribs['_removed_id'] = ['new-1']
2979
        attribs['_removed_contents'] = ['new-2']
2980
        attribs['_tree_path_ids'] = {
2981
            '': 'new-0',
2982
            u'foo\u1234'.encode('utf-8'): 'new-1',
2983
            'bar': 'new-2',
2984
            }
2985
        return self.make_records(attribs, [])
2986
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
2987
    def test_serialize_destruction(self):
0.13.19 by Aaron Bentley
Clean up serialization tests
2988
        tt = self.make_destruction_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
2989
        foo_trans_id = tt.trans_id_tree_file_id('foo-id')
2990
        tt.unversion_file(foo_trans_id)
2991
        bar_trans_id = tt.trans_id_tree_file_id('bar-id')
2992
        tt.delete_contents(bar_trans_id)
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
2993
        self.assertSerializesTo(self.destruction_records(), tt)
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
2994
2995
    def test_deserialize_destruction(self):
0.13.19 by Aaron Bentley
Clean up serialization tests
2996
        tt = self.make_destruction_preview()
0.13.17 by Aaron Bentley
Convert roundtrip destruction test to serialization/deserialization pair
2997
        tt.deserialize(iter(self.destruction_records()))
2998
        self.assertEqual({u'foo\u1234': 'new-1',
2999
                          'bar': 'new-2',
3000
                          '': tt.root}, tt._tree_path_ids)
3001
        self.assertEqual({'new-1': u'foo\u1234',
3002
                          'new-2': 'bar',
3003
                          tt.root: ''}, tt._tree_id_paths)
3004
        self.assertEqual(set(['new-1']), tt._removed_id)
3005
        self.assertEqual(set(['new-2']), tt._removed_contents)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3006
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3007
    def missing_records(self):
3008
        attribs = self.default_attribs()
3009
        attribs['_id_number'] = 2
3010
        attribs['_non_present_ids'] = {
3011
            'boo': 'new-1',}
3012
        return self.make_records(attribs, [])
3013
3014
    def test_serialize_missing(self):
3015
        tt = self.get_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3016
        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
3017
        self.assertSerializesTo(self.missing_records(), tt)
3018
3019
    def test_deserialize_missing(self):
3020
        tt = self.get_preview()
3021
        tt.deserialize(iter(self.missing_records()))
3022
        self.assertEqual({'boo': 'new-1'}, tt._non_present_ids)
3023
3024
    def make_modification_preview(self):
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3025
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
3026
        LINES_TWO = 'z\nbb\nx\ndd\n'
3027
        tree = self.make_branch_and_tree('tree')
3028
        self.build_tree_contents([('tree/file', LINES_ONE)])
3029
        tree.add('file', 'file-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3030
        return self.get_preview(tree), LINES_TWO
3031
3032
    def modification_records(self):
3033
        attribs = self.default_attribs()
3034
        attribs['_id_number'] = 2
3035
        attribs['_tree_path_ids'] = {
3036
            'file': 'new-1',
3037
            '': 'new-0',}
3038
        attribs['_removed_contents'] = ['new-1']
3039
        contents = [('new-1', 'file',
3040
                     'i 1\nz\n\nc 0 1 1 1\ni 1\nx\n\nc 0 3 3 1\n')]
3041
        return self.make_records(attribs, contents)
3042
3043
    def test_serialize_modification(self):
3044
        tt, LINES = self.make_modification_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3045
        trans_id = tt.trans_id_file_id('file-id')
3046
        tt.delete_contents(trans_id)
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3047
        tt.create_file(LINES, trans_id)
3048
        self.assertSerializesTo(self.modification_records(), tt)
3049
3050
    def test_deserialize_modification(self):
3051
        tt, LINES = self.make_modification_preview()
3052
        tt.deserialize(iter(self.modification_records()))
3053
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
3054
3055
    def make_kind_change_preview(self):
3056
        LINES = 'a\nb\nc\nd\n'
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3057
        tree = self.make_branch_and_tree('tree')
3058
        self.build_tree(['tree/foo/'])
3059
        tree.add('foo', 'foo-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3060
        return self.get_preview(tree), LINES
3061
3062
    def kind_change_records(self):
3063
        attribs = self.default_attribs()
3064
        attribs['_id_number'] = 2
3065
        attribs['_tree_path_ids'] = {
3066
            'foo': 'new-1',
3067
            '': 'new-0',}
3068
        attribs['_removed_contents'] = ['new-1']
3069
        contents = [('new-1', 'file',
3070
                     'i 4\na\nb\nc\nd\n\n')]
3071
        return self.make_records(attribs, contents)
3072
3073
    def test_serialize_kind_change(self):
3074
        tt, LINES = self.make_kind_change_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3075
        trans_id = tt.trans_id_file_id('foo-id')
3076
        tt.delete_contents(trans_id)
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3077
        tt.create_file(LINES, trans_id)
3078
        self.assertSerializesTo(self.kind_change_records(), tt)
3079
3080
    def test_deserialize_kind_change(self):
3081
        tt, LINES = self.make_kind_change_preview()
3082
        tt.deserialize(iter(self.kind_change_records()))
3083
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
3084
3085
    def make_add_contents_preview(self):
3086
        LINES = 'a\nb\nc\nd\n'
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3087
        tree = self.make_branch_and_tree('tree')
3088
        self.build_tree(['tree/foo'])
3089
        tree.add('foo')
3090
        os.unlink('tree/foo')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3091
        return self.get_preview(tree), LINES
3092
3093
    def add_contents_records(self):
3094
        attribs = self.default_attribs()
3095
        attribs['_id_number'] = 2
3096
        attribs['_tree_path_ids'] = {
3097
            'foo': 'new-1',
3098
            '': 'new-0',}
3099
        contents = [('new-1', 'file',
3100
                     'i 4\na\nb\nc\nd\n\n')]
3101
        return self.make_records(attribs, contents)
3102
3103
    def test_serialize_add_contents(self):
3104
        tt, LINES = self.make_add_contents_preview()
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3105
        trans_id = tt.trans_id_tree_path('foo')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3106
        tt.create_file(LINES, trans_id)
3107
        self.assertSerializesTo(self.add_contents_records(), tt)
3108
3109
    def test_deserialize_add_contents(self):
3110
        tt, LINES = self.make_add_contents_preview()
3111
        tt.deserialize(iter(self.add_contents_records()))
3112
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3113
3114
    def test_get_parents_lines(self):
3115
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
3116
        LINES_TWO = 'z\nbb\nx\ndd\n'
3117
        tree = self.make_branch_and_tree('tree')
3118
        self.build_tree_contents([('tree/file', LINES_ONE)])
3119
        tree.add('file', 'file-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3120
        tt = self.get_preview(tree)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3121
        trans_id = tt.trans_id_tree_path('file')
3122
        self.assertEqual((['aa\n', 'bb\n', 'cc\n', 'dd\n'],),
3123
            tt._get_parents_lines(trans_id))
3124
3125
    def test_get_parents_texts(self):
3126
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
3127
        LINES_TWO = 'z\nbb\nx\ndd\n'
3128
        tree = self.make_branch_and_tree('tree')
3129
        self.build_tree_contents([('tree/file', LINES_ONE)])
3130
        tree.add('file', 'file-id')
0.13.18 by Aaron Bentley
Finish converting tests to direct serialize/deserialize tests, clean up
3131
        tt = self.get_preview(tree)
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
3132
        trans_id = tt.trans_id_tree_path('file')
3133
        self.assertEqual((LINES_ONE,),
3134
            tt._get_parents_texts(trans_id))