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