/brz/remove-bazaar

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