/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1534.7.106 by Aaron Bentley
Cleaned up imports, added copyright statements
1
# Copyright (C) 2006 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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
import os
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
18
import stat
19
import sys
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
20
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
21
from bzrlib import (
2090.2.1 by Martin Pool
Fix some code which relies on assertions and breaks under python -O
22
    errors,
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
23
    generate_ids,
2255.7.48 by Robert Collins
Deprecated and make work with DirState trees 'transform.find_interesting'.
24
    symbol_versioning,
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
25
    tests,
26
    urlutils,
27
    )
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
28
from bzrlib.bzrdir import BzrDir
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
29
from bzrlib.conflicts import (DuplicateEntry, DuplicateID, MissingParent,
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
30
                              UnversionedParent, ParentLoop, DeletingParent,)
1534.7.32 by Aaron Bentley
Got conflict handling working when conflicts involve existing files
31
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
1551.7.17 by Aaron Bentley
Switch to PathsNotVersioned, accept extra_trees
32
                           ReusingTransform, CantMoveRoot, 
33
                           PathsNotVersionedError, ExistingLimbo,
34
                           ImmortalLimbo, LockError)
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
35
from bzrlib.osutils import file_kind, has_symlinks, pathjoin
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
36
from bzrlib.merge import Merge3Merger
1534.10.28 by Aaron Bentley
Use numbered backup files
37
from bzrlib.tests import TestCaseInTempDir, TestSkipped, TestCase
1534.7.106 by Aaron Bentley
Cleaned up imports, added copyright statements
38
from bzrlib.transform import (TreeTransform, ROOT_PARENT, FinalPaths, 
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
39
                              resolve_conflicts, cook_conflicts, 
1534.10.28 by Aaron Bentley
Use numbered backup files
40
                              find_interesting, build_tree, get_backup_name)
1731.1.33 by Aaron Bentley
Revert no-special-root changes
41
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
42
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
43
class TestTreeTransform(tests.TestCaseWithTransport):
1740.2.4 by Aaron Bentley
Update transform tests and docs
44
1534.7.59 by Aaron Bentley
Simplified tests
45
    def setUp(self):
46
        super(TestTreeTransform, self).setUp()
2255.2.174 by Martin Pool
remove AB1 WorkingTree and experimental-knit3
47
        self.wt = self.make_branch_and_tree('.', format='experimental-reference-dirstate')
1534.7.161 by Aaron Bentley
Used appropriate control_files
48
        os.chdir('..')
1534.7.59 by Aaron Bentley
Simplified tests
49
50
    def get_transform(self):
51
        transform = TreeTransform(self.wt)
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
52
        #self.addCleanup(transform.finalize)
1731.1.33 by Aaron Bentley
Revert no-special-root changes
53
        return transform, transform.root
1534.7.59 by Aaron Bentley
Simplified tests
54
1534.7.162 by Aaron Bentley
Handle failures creating/deleting the Limbo directory
55
    def test_existing_limbo(self):
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
56
        limbo_name = urlutils.local_path_from_url(
1685.1.16 by John Arbash Meinel
A few places that were comparing a working trees base to a branch's base, where Branch.base is now a URL
57
            self.wt._control_files.controlfilename('limbo'))
1534.7.162 by Aaron Bentley
Handle failures creating/deleting the Limbo directory
58
        transform, root = self.get_transform()
1534.7.176 by abentley
Fixed up tests for Windows
59
        os.mkdir(pathjoin(limbo_name, 'hehe'))
1534.7.162 by Aaron Bentley
Handle failures creating/deleting the Limbo directory
60
        self.assertRaises(ImmortalLimbo, transform.apply)
61
        self.assertRaises(LockError, self.wt.unlock)
62
        self.assertRaises(ExistingLimbo, self.get_transform)
63
        self.assertRaises(LockError, self.wt.unlock)
1534.7.176 by abentley
Fixed up tests for Windows
64
        os.rmdir(pathjoin(limbo_name, 'hehe'))
1534.7.162 by Aaron Bentley
Handle failures creating/deleting the Limbo directory
65
        os.rmdir(limbo_name)
66
        transform, root = self.get_transform()
67
        transform.apply()
1534.7.59 by Aaron Bentley
Simplified tests
68
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
69
    def test_build(self):
1534.7.59 by Aaron Bentley
Simplified tests
70
        transform, root = self.get_transform() 
71
        self.assertIs(transform.get_tree_parent(root), ROOT_PARENT)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
72
        imaginary_id = transform.trans_id_tree_path('imaginary')
1534.10.32 by Aaron Bentley
Test and fix case where name has trailing slash
73
        imaginary_id2 = transform.trans_id_tree_path('imaginary/')
74
        self.assertEqual(imaginary_id, imaginary_id2)
1534.7.59 by Aaron Bentley
Simplified tests
75
        self.assertEqual(transform.get_tree_parent(imaginary_id), root)
76
        self.assertEqual(transform.final_kind(root), 'directory')
77
        self.assertEqual(transform.final_file_id(root), self.wt.get_root_id())
78
        trans_id = transform.create_path('name', root)
79
        self.assertIs(transform.final_file_id(trans_id), None)
80
        self.assertRaises(NoSuchFile, transform.final_kind, trans_id)
81
        transform.create_file('contents', trans_id)
82
        transform.set_executability(True, trans_id)
83
        transform.version_file('my_pretties', trans_id)
84
        self.assertRaises(DuplicateKey, transform.version_file,
85
                          'my_pretties', trans_id)
86
        self.assertEqual(transform.final_file_id(trans_id), 'my_pretties')
87
        self.assertEqual(transform.final_parent(trans_id), root)
88
        self.assertIs(transform.final_parent(root), ROOT_PARENT)
89
        self.assertIs(transform.get_tree_parent(root), ROOT_PARENT)
90
        oz_id = transform.create_path('oz', root)
91
        transform.create_directory(oz_id)
92
        transform.version_file('ozzie', oz_id)
93
        trans_id2 = transform.create_path('name2', root)
94
        transform.create_file('contents', trans_id2)
95
        transform.set_executability(False, trans_id2)
96
        transform.version_file('my_pretties2', trans_id2)
1534.7.191 by Aaron Bentley
Got transform.apply to list modified paths
97
        modified_paths = transform.apply().modified_paths
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
98
        self.assertEqual('contents', self.wt.get_file_byname('name').read())
1534.7.59 by Aaron Bentley
Simplified tests
99
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
100
        self.assertIs(self.wt.is_executable('my_pretties'), True)
101
        self.assertIs(self.wt.is_executable('my_pretties2'), False)
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
102
        self.assertEqual('directory', file_kind(self.wt.abspath('oz')))
1534.7.191 by Aaron Bentley
Got transform.apply to list modified paths
103
        self.assertEqual(len(modified_paths), 3)
104
        tree_mod_paths = [self.wt.id2abspath(f) for f in 
105
                          ('ozzie', 'my_pretties', 'my_pretties2')]
106
        self.assertSubset(tree_mod_paths, modified_paths)
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
107
        # is it safe to finalize repeatedly?
108
        transform.finalize()
1534.7.59 by Aaron Bentley
Simplified tests
109
        transform.finalize()
1534.7.2 by Aaron Bentley
Added convenience function
110
111
    def test_convenience(self):
1534.7.59 by Aaron Bentley
Simplified tests
112
        transform, root = self.get_transform()
113
        trans_id = transform.new_file('name', root, 'contents', 
114
                                      'my_pretties', True)
115
        oz = transform.new_directory('oz', root, 'oz-id')
116
        dorothy = transform.new_directory('dorothy', oz, 'dorothy-id')
117
        toto = transform.new_file('toto', dorothy, 'toto-contents', 
118
                                  'toto-id', False)
119
120
        self.assertEqual(len(transform.find_conflicts()), 0)
121
        transform.apply()
122
        self.assertRaises(ReusingTransform, transform.find_conflicts)
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
123
        self.assertEqual('contents', file(self.wt.abspath('name')).read())
1534.7.59 by Aaron Bentley
Simplified tests
124
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
125
        self.assertIs(self.wt.is_executable('my_pretties'), True)
126
        self.assertEqual(self.wt.path2id('oz'), 'oz-id')
127
        self.assertEqual(self.wt.path2id('oz/dorothy'), 'dorothy-id')
128
        self.assertEqual(self.wt.path2id('oz/dorothy/toto'), 'toto-id')
129
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
130
        self.assertEqual('toto-contents', 
131
                         self.wt.get_file_byname('oz/dorothy/toto').read())
1534.7.59 by Aaron Bentley
Simplified tests
132
        self.assertIs(self.wt.is_executable('toto-id'), False)
1534.7.6 by Aaron Bentley
Added conflict handling
133
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
134
    def test_tree_reference(self):
135
        transform, root = self.get_transform()
136
        tree = transform._tree
137
        trans_id = transform.new_directory('reference', root, 'subtree-id')
138
        transform.set_tree_reference('subtree-revision', trans_id)
139
        transform.apply()
140
        self.assertEqual('subtree-revision', 
141
                         tree.inventory['subtree-id'].reference_revision)
142
1534.7.6 by Aaron Bentley
Added conflict handling
143
    def test_conflicts(self):
1534.7.59 by Aaron Bentley
Simplified tests
144
        transform, root = self.get_transform()
145
        trans_id = transform.new_file('name', root, 'contents', 
146
                                      'my_pretties')
147
        self.assertEqual(len(transform.find_conflicts()), 0)
148
        trans_id2 = transform.new_file('name', root, 'Crontents', 'toto')
149
        self.assertEqual(transform.find_conflicts(), 
150
                         [('duplicate', trans_id, trans_id2, 'name')])
151
        self.assertRaises(MalformedTransform, transform.apply)
152
        transform.adjust_path('name', trans_id, trans_id2)
153
        self.assertEqual(transform.find_conflicts(), 
154
                         [('non-directory parent', trans_id)])
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
155
        tinman_id = transform.trans_id_tree_path('tinman')
1534.7.59 by Aaron Bentley
Simplified tests
156
        transform.adjust_path('name', tinman_id, trans_id2)
157
        self.assertEqual(transform.find_conflicts(), 
158
                         [('unversioned parent', tinman_id), 
159
                          ('missing parent', tinman_id)])
160
        lion_id = transform.create_path('lion', root)
161
        self.assertEqual(transform.find_conflicts(), 
162
                         [('unversioned parent', tinman_id), 
163
                          ('missing parent', tinman_id)])
164
        transform.adjust_path('name', lion_id, trans_id2)
165
        self.assertEqual(transform.find_conflicts(), 
166
                         [('unversioned parent', lion_id),
167
                          ('missing parent', lion_id)])
168
        transform.version_file("Courage", lion_id)
169
        self.assertEqual(transform.find_conflicts(), 
170
                         [('missing parent', lion_id), 
171
                          ('versioning no contents', lion_id)])
172
        transform.adjust_path('name2', root, trans_id2)
173
        self.assertEqual(transform.find_conflicts(), 
174
                         [('versioning no contents', lion_id)])
175
        transform.create_file('Contents, okay?', lion_id)
176
        transform.adjust_path('name2', trans_id2, trans_id2)
177
        self.assertEqual(transform.find_conflicts(), 
178
                         [('parent loop', trans_id2), 
179
                          ('non-directory parent', trans_id2)])
180
        transform.adjust_path('name2', root, trans_id2)
181
        oz_id = transform.new_directory('oz', root)
182
        transform.set_executability(True, oz_id)
183
        self.assertEqual(transform.find_conflicts(), 
184
                         [('unversioned executability', oz_id)])
185
        transform.version_file('oz-id', oz_id)
186
        self.assertEqual(transform.find_conflicts(), 
187
                         [('non-file executability', oz_id)])
188
        transform.set_executability(None, oz_id)
1534.7.71 by abentley
All tests pass under Windows
189
        tip_id = transform.new_file('tip', oz_id, 'ozma', 'tip-id')
1534.7.59 by Aaron Bentley
Simplified tests
190
        transform.apply()
191
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
192
        self.assertEqual('contents', file(self.wt.abspath('name')).read())
193
        transform2, root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
194
        oz_id = transform2.trans_id_tree_file_id('oz-id')
1534.7.59 by Aaron Bentley
Simplified tests
195
        newtip = transform2.new_file('tip', oz_id, 'other', 'tip-id')
196
        result = transform2.find_conflicts()
1534.7.135 by Aaron Bentley
Fixed deletion handling
197
        fp = FinalPaths(transform2)
1534.7.59 by Aaron Bentley
Simplified tests
198
        self.assert_('oz/tip' in transform2._tree_path_ids)
1534.7.176 by abentley
Fixed up tests for Windows
199
        self.assertEqual(fp.get_path(newtip), pathjoin('oz', 'tip'))
1534.7.59 by Aaron Bentley
Simplified tests
200
        self.assertEqual(len(result), 2)
201
        self.assertEqual((result[0][0], result[0][1]), 
202
                         ('duplicate', newtip))
203
        self.assertEqual((result[1][0], result[1][2]), 
204
                         ('duplicate id', newtip))
1534.7.73 by Aaron Bentley
Changed model again. Now iterator is used immediately.
205
        transform2.finalize()
1534.7.59 by Aaron Bentley
Simplified tests
206
        transform3 = TreeTransform(self.wt)
207
        self.addCleanup(transform3.finalize)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
208
        oz_id = transform3.trans_id_tree_file_id('oz-id')
1534.7.59 by Aaron Bentley
Simplified tests
209
        transform3.delete_contents(oz_id)
210
        self.assertEqual(transform3.find_conflicts(), 
211
                         [('missing parent', oz_id)])
1731.1.33 by Aaron Bentley
Revert no-special-root changes
212
        root_id = transform3.root
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
213
        tip_id = transform3.trans_id_tree_file_id('tip-id')
1534.7.59 by Aaron Bentley
Simplified tests
214
        transform3.adjust_path('tip', root_id, tip_id)
215
        transform3.apply()
1534.7.36 by Aaron Bentley
Added rename tests
216
1558.7.11 by Aaron Bentley
Avoid spurious conflict on add/delete
217
    def test_add_del(self):
218
        start, root = self.get_transform()
219
        start.new_directory('a', root, 'a')
220
        start.apply()
221
        transform, root = self.get_transform()
222
        transform.delete_versioned(transform.trans_id_tree_file_id('a'))
223
        transform.new_directory('a', root, 'a')
224
        transform.apply()
225
1534.7.46 by Aaron Bentley
Ensured a conflict when parents of versioned files are unversioned
226
    def test_unversioning(self):
1534.7.59 by Aaron Bentley
Simplified tests
227
        create_tree, root = self.get_transform()
228
        parent_id = create_tree.new_directory('parent', root, 'parent-id')
229
        create_tree.new_file('child', parent_id, 'child', 'child-id')
230
        create_tree.apply()
231
        unversion = TreeTransform(self.wt)
232
        self.addCleanup(unversion.finalize)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
233
        parent = unversion.trans_id_tree_path('parent')
1534.7.59 by Aaron Bentley
Simplified tests
234
        unversion.unversion_file(parent)
235
        self.assertEqual(unversion.find_conflicts(), 
236
                         [('unversioned parent', parent_id)])
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
237
        file_id = unversion.trans_id_tree_file_id('child-id')
1534.7.59 by Aaron Bentley
Simplified tests
238
        unversion.unversion_file(file_id)
239
        unversion.apply()
1534.7.46 by Aaron Bentley
Ensured a conflict when parents of versioned files are unversioned
240
1534.7.36 by Aaron Bentley
Added rename tests
241
    def test_name_invariants(self):
1534.7.59 by Aaron Bentley
Simplified tests
242
        create_tree, root = self.get_transform()
243
        # prepare tree
1731.1.33 by Aaron Bentley
Revert no-special-root changes
244
        root = create_tree.root
1534.7.59 by Aaron Bentley
Simplified tests
245
        create_tree.new_file('name1', root, 'hello1', 'name1')
246
        create_tree.new_file('name2', root, 'hello2', 'name2')
247
        ddir = create_tree.new_directory('dying_directory', root, 'ddir')
248
        create_tree.new_file('dying_file', ddir, 'goodbye1', 'dfile')
249
        create_tree.new_file('moving_file', ddir, 'later1', 'mfile')
250
        create_tree.new_file('moving_file2', root, 'later2', 'mfile2')
251
        create_tree.apply()
252
253
        mangle_tree,root = self.get_transform()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
254
        root = mangle_tree.root
1534.7.59 by Aaron Bentley
Simplified tests
255
        #swap names
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
256
        name1 = mangle_tree.trans_id_tree_file_id('name1')
257
        name2 = mangle_tree.trans_id_tree_file_id('name2')
1534.7.59 by Aaron Bentley
Simplified tests
258
        mangle_tree.adjust_path('name2', root, name1)
259
        mangle_tree.adjust_path('name1', root, name2)
260
261
        #tests for deleting parent directories 
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
262
        ddir = mangle_tree.trans_id_tree_file_id('ddir')
1534.7.59 by Aaron Bentley
Simplified tests
263
        mangle_tree.delete_contents(ddir)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
264
        dfile = mangle_tree.trans_id_tree_file_id('dfile')
1534.7.59 by Aaron Bentley
Simplified tests
265
        mangle_tree.delete_versioned(dfile)
266
        mangle_tree.unversion_file(dfile)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
267
        mfile = mangle_tree.trans_id_tree_file_id('mfile')
1534.7.59 by Aaron Bentley
Simplified tests
268
        mangle_tree.adjust_path('mfile', root, mfile)
269
270
        #tests for adding parent directories
271
        newdir = mangle_tree.new_directory('new_directory', root, 'newdir')
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
272
        mfile2 = mangle_tree.trans_id_tree_file_id('mfile2')
1534.7.59 by Aaron Bentley
Simplified tests
273
        mangle_tree.adjust_path('mfile2', newdir, mfile2)
274
        mangle_tree.new_file('newfile', newdir, 'hello3', 'dfile')
275
        self.assertEqual(mangle_tree.final_file_id(mfile2), 'mfile2')
276
        self.assertEqual(mangle_tree.final_parent(mfile2), newdir)
277
        self.assertEqual(mangle_tree.final_file_id(mfile2), 'mfile2')
278
        mangle_tree.apply()
279
        self.assertEqual(file(self.wt.abspath('name1')).read(), 'hello2')
280
        self.assertEqual(file(self.wt.abspath('name2')).read(), 'hello1')
1534.7.176 by abentley
Fixed up tests for Windows
281
        mfile2_path = self.wt.abspath(pathjoin('new_directory','mfile2'))
1534.7.41 by Aaron Bentley
Got inventory ID movement working
282
        self.assertEqual(mangle_tree.final_parent(mfile2), newdir)
1534.7.38 by Aaron Bentley
Tested adding paths
283
        self.assertEqual(file(mfile2_path).read(), 'later2')
1534.7.59 by Aaron Bentley
Simplified tests
284
        self.assertEqual(self.wt.id2path('mfile2'), 'new_directory/mfile2')
285
        self.assertEqual(self.wt.path2id('new_directory/mfile2'), 'mfile2')
1534.7.176 by abentley
Fixed up tests for Windows
286
        newfile_path = self.wt.abspath(pathjoin('new_directory','newfile'))
1534.7.38 by Aaron Bentley
Tested adding paths
287
        self.assertEqual(file(newfile_path).read(), 'hello3')
1534.7.59 by Aaron Bentley
Simplified tests
288
        self.assertEqual(self.wt.path2id('dying_directory'), 'ddir')
289
        self.assertIs(self.wt.path2id('dying_directory/dying_file'), None)
1534.7.176 by abentley
Fixed up tests for Windows
290
        mfile2_path = self.wt.abspath(pathjoin('new_directory','mfile2'))
1534.7.43 by abentley
Fixed some Windows bugs, introduced a conflicts bug
291
1534.7.150 by Aaron Bentley
Handled simultaneous renames of parent and child better
292
    def test_both_rename(self):
293
        create_tree,root = self.get_transform()
294
        newdir = create_tree.new_directory('selftest', root, 'selftest-id')
295
        create_tree.new_file('blackbox.py', newdir, 'hello1', 'blackbox-id')
296
        create_tree.apply()        
297
        mangle_tree,root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
298
        selftest = mangle_tree.trans_id_tree_file_id('selftest-id')
299
        blackbox = mangle_tree.trans_id_tree_file_id('blackbox-id')
1534.7.150 by Aaron Bentley
Handled simultaneous renames of parent and child better
300
        mangle_tree.adjust_path('test', root, selftest)
301
        mangle_tree.adjust_path('test_too_much', root, selftest)
302
        mangle_tree.set_executability(True, blackbox)
303
        mangle_tree.apply()
304
305
    def test_both_rename2(self):
306
        create_tree,root = self.get_transform()
307
        bzrlib = create_tree.new_directory('bzrlib', root, 'bzrlib-id')
308
        tests = create_tree.new_directory('tests', bzrlib, 'tests-id')
309
        blackbox = create_tree.new_directory('blackbox', tests, 'blackbox-id')
310
        create_tree.new_file('test_too_much.py', blackbox, 'hello1', 
311
                             'test_too_much-id')
312
        create_tree.apply()        
313
        mangle_tree,root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
314
        bzrlib = mangle_tree.trans_id_tree_file_id('bzrlib-id')
315
        tests = mangle_tree.trans_id_tree_file_id('tests-id')
316
        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
317
        mangle_tree.adjust_path('selftest', bzrlib, tests)
318
        mangle_tree.adjust_path('blackbox.py', tests, test_too_much) 
319
        mangle_tree.set_executability(True, test_too_much)
320
        mangle_tree.apply()
321
322
    def test_both_rename3(self):
323
        create_tree,root = self.get_transform()
324
        tests = create_tree.new_directory('tests', root, 'tests-id')
325
        create_tree.new_file('test_too_much.py', tests, 'hello1', 
326
                             'test_too_much-id')
327
        create_tree.apply()        
328
        mangle_tree,root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
329
        tests = mangle_tree.trans_id_tree_file_id('tests-id')
330
        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
331
        mangle_tree.adjust_path('selftest', root, tests)
332
        mangle_tree.adjust_path('blackbox.py', tests, test_too_much) 
333
        mangle_tree.set_executability(True, test_too_much)
334
        mangle_tree.apply()
335
1534.7.48 by Aaron Bentley
Ensured we can move/rename dangling inventory entries
336
    def test_move_dangling_ie(self):
1534.7.59 by Aaron Bentley
Simplified tests
337
        create_tree, root = self.get_transform()
338
        # prepare tree
1731.1.33 by Aaron Bentley
Revert no-special-root changes
339
        root = create_tree.root
1534.7.59 by Aaron Bentley
Simplified tests
340
        create_tree.new_file('name1', root, 'hello1', 'name1')
341
        create_tree.apply()
342
        delete_contents, root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
343
        file = delete_contents.trans_id_tree_file_id('name1')
1534.7.59 by Aaron Bentley
Simplified tests
344
        delete_contents.delete_contents(file)
345
        delete_contents.apply()
346
        move_id, root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
347
        name1 = move_id.trans_id_tree_file_id('name1')
1534.7.59 by Aaron Bentley
Simplified tests
348
        newdir = move_id.new_directory('dir', root, 'newdir')
349
        move_id.adjust_path('name2', newdir, name1)
350
        move_id.apply()
1534.7.48 by Aaron Bentley
Ensured we can move/rename dangling inventory entries
351
        
1534.7.50 by Aaron Bentley
Detect duplicate inventory ids
352
    def test_replace_dangling_ie(self):
1534.7.59 by Aaron Bentley
Simplified tests
353
        create_tree, root = self.get_transform()
354
        # prepare tree
1731.1.33 by Aaron Bentley
Revert no-special-root changes
355
        root = create_tree.root
1534.7.59 by Aaron Bentley
Simplified tests
356
        create_tree.new_file('name1', root, 'hello1', 'name1')
357
        create_tree.apply()
358
        delete_contents = TreeTransform(self.wt)
359
        self.addCleanup(delete_contents.finalize)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
360
        file = delete_contents.trans_id_tree_file_id('name1')
1534.7.59 by Aaron Bentley
Simplified tests
361
        delete_contents.delete_contents(file)
362
        delete_contents.apply()
363
        delete_contents.finalize()
364
        replace = TreeTransform(self.wt)
365
        self.addCleanup(replace.finalize)
366
        name2 = replace.new_file('name2', root, 'hello2', 'name1')
367
        conflicts = replace.find_conflicts()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
368
        name1 = replace.trans_id_tree_file_id('name1')
1534.7.59 by Aaron Bentley
Simplified tests
369
        self.assertEqual(conflicts, [('duplicate id', name1, name2)])
370
        resolve_conflicts(replace)
371
        replace.apply()
1534.7.48 by Aaron Bentley
Ensured we can move/rename dangling inventory entries
372
1534.7.43 by abentley
Fixed some Windows bugs, introduced a conflicts bug
373
    def test_symlinks(self):
1534.7.45 by Aaron Bentley
Skipped symlink test more correctly
374
        if not has_symlinks():
375
            raise TestSkipped('Symlinks are not supported on this platform')
1534.7.59 by Aaron Bentley
Simplified tests
376
        transform,root = self.get_transform()
377
        oz_id = transform.new_directory('oz', root, 'oz-id')
378
        wizard = transform.new_symlink('wizard', oz_id, 'wizard-target', 
379
                                       'wizard-id')
380
        wiz_id = transform.create_path('wizard2', oz_id)
381
        transform.create_symlink('behind_curtain', wiz_id)
382
        transform.version_file('wiz-id2', wiz_id)            
1534.7.71 by abentley
All tests pass under Windows
383
        transform.set_executability(True, wiz_id)
384
        self.assertEqual(transform.find_conflicts(), 
385
                         [('non-file executability', wiz_id)])
386
        transform.set_executability(None, wiz_id)
1534.7.59 by Aaron Bentley
Simplified tests
387
        transform.apply()
388
        self.assertEqual(self.wt.path2id('oz/wizard'), 'wizard-id')
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
389
        self.assertEqual(file_kind(self.wt.abspath('oz/wizard')), 'symlink')
390
        self.assertEqual(os.readlink(self.wt.abspath('oz/wizard2')), 
391
                         'behind_curtain')
392
        self.assertEqual(os.readlink(self.wt.abspath('oz/wizard')),
393
                         'wizard-target')
1534.7.60 by Aaron Bentley
Tested existing conflict resolution functionality
394
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
395
396
    def get_conflicted(self):
1534.7.60 by Aaron Bentley
Tested existing conflict resolution functionality
397
        create,root = self.get_transform()
398
        create.new_file('dorothy', root, 'dorothy', 'dorothy-id')
1534.7.61 by Aaron Bentley
Handled parent loops, missing parents, unversioned parents
399
        oz = create.new_directory('oz', root, 'oz-id')
400
        create.new_directory('emeraldcity', oz, 'emerald-id')
1534.7.60 by Aaron Bentley
Tested existing conflict resolution functionality
401
        create.apply()
402
        conflicts,root = self.get_transform()
1534.7.65 by Aaron Bentley
Text cleaup/docs
403
        # set up duplicate entry, duplicate id
1534.7.60 by Aaron Bentley
Tested existing conflict resolution functionality
404
        new_dorothy = conflicts.new_file('dorothy', root, 'dorothy', 
405
                                         'dorothy-id')
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
406
        old_dorothy = conflicts.trans_id_tree_file_id('dorothy-id')
407
        oz = conflicts.trans_id_tree_file_id('oz-id')
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
408
        # set up DeletedParent parent conflict
1534.7.65 by Aaron Bentley
Text cleaup/docs
409
        conflicts.delete_versioned(oz)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
410
        emerald = conflicts.trans_id_tree_file_id('emerald-id')
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
411
        # set up MissingParent conflict
412
        munchkincity = conflicts.trans_id_file_id('munchkincity-id')
413
        conflicts.adjust_path('munchkincity', root, munchkincity)
414
        conflicts.new_directory('auntem', munchkincity, 'auntem-id')
1534.7.65 by Aaron Bentley
Text cleaup/docs
415
        # set up parent loop
1534.7.61 by Aaron Bentley
Handled parent loops, missing parents, unversioned parents
416
        conflicts.adjust_path('emeraldcity', emerald, emerald)
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
417
        return conflicts, emerald, oz, old_dorothy, new_dorothy
418
419
    def test_conflict_resolution(self):
420
        conflicts, emerald, oz, old_dorothy, new_dorothy =\
421
            self.get_conflicted()
1534.7.60 by Aaron Bentley
Tested existing conflict resolution functionality
422
        resolve_conflicts(conflicts)
423
        self.assertEqual(conflicts.final_name(old_dorothy), 'dorothy.moved')
424
        self.assertIs(conflicts.final_file_id(old_dorothy), None)
425
        self.assertEqual(conflicts.final_name(new_dorothy), 'dorothy')
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
426
        self.assertEqual(conflicts.final_file_id(new_dorothy), 'dorothy-id')
1534.7.64 by Aaron Bentley
Extra testing
427
        self.assertEqual(conflicts.final_parent(emerald), oz)
1534.7.63 by Aaron Bentley
Ensure transform can be applied after resolution
428
        conflicts.apply()
1534.7.62 by Aaron Bentley
Fixed moving versioned directories
429
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
430
    def test_cook_conflicts(self):
431
        tt, emerald, oz, old_dorothy, new_dorothy = self.get_conflicted()
432
        raw_conflicts = resolve_conflicts(tt)
433
        cooked_conflicts = cook_conflicts(raw_conflicts, tt)
1534.10.20 by Aaron Bentley
Got all tests passing
434
        duplicate = DuplicateEntry('Moved existing file to', 'dorothy.moved', 
435
                                   'dorothy', None, 'dorothy-id')
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
436
        self.assertEqual(cooked_conflicts[0], duplicate)
1534.10.20 by Aaron Bentley
Got all tests passing
437
        duplicate_id = DuplicateID('Unversioned existing file', 
438
                                   'dorothy.moved', 'dorothy', None,
439
                                   'dorothy-id')
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
440
        self.assertEqual(cooked_conflicts[1], duplicate_id)
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
441
        missing_parent = MissingParent('Created directory', 'munchkincity',
442
                                       'munchkincity-id')
443
        deleted_parent = DeletingParent('Not deleting', 'oz', 'oz-id')
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
444
        self.assertEqual(cooked_conflicts[2], missing_parent)
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
445
        unversioned_parent = UnversionedParent('Versioned directory',
446
                                               'munchkincity',
447
                                               'munchkincity-id')
448
        unversioned_parent2 = UnversionedParent('Versioned directory', 'oz',
1534.10.20 by Aaron Bentley
Got all tests passing
449
                                               'oz-id')
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
450
        self.assertEqual(cooked_conflicts[3], unversioned_parent)
1534.10.20 by Aaron Bentley
Got all tests passing
451
        parent_loop = ParentLoop('Cancelled move', 'oz/emeraldcity', 
452
                                 'oz/emeraldcity', 'emerald-id', 'emerald-id')
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
453
        self.assertEqual(cooked_conflicts[4], deleted_parent)
454
        self.assertEqual(cooked_conflicts[5], unversioned_parent2)
455
        self.assertEqual(cooked_conflicts[6], parent_loop)
456
        self.assertEqual(len(cooked_conflicts), 7)
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
457
        tt.finalize()
458
459
    def test_string_conflicts(self):
460
        tt, emerald, oz, old_dorothy, new_dorothy = self.get_conflicted()
461
        raw_conflicts = resolve_conflicts(tt)
462
        cooked_conflicts = cook_conflicts(raw_conflicts, tt)
463
        tt.finalize()
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
464
        conflicts_s = [str(c) for c in cooked_conflicts]
1534.7.171 by Aaron Bentley
Implemented stringifying filesystem conflicts
465
        self.assertEqual(len(cooked_conflicts), len(conflicts_s))
466
        self.assertEqual(conflicts_s[0], 'Conflict adding file dorothy.  '
467
                                         'Moved existing file to '
468
                                         'dorothy.moved.')
469
        self.assertEqual(conflicts_s[1], 'Conflict adding id to dorothy.  '
470
                                         'Unversioned existing file '
471
                                         'dorothy.moved.')
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
472
        self.assertEqual(conflicts_s[2], 'Conflict adding files to'
473
                                         ' munchkincity.  Created directory.')
474
        self.assertEqual(conflicts_s[3], 'Conflict because munchkincity is not'
475
                                         ' versioned, but has versioned'
476
                                         ' children.  Versioned directory.')
1551.8.23 by Aaron Bentley
Tweaked conflict message to be more understandable
477
        self.assertEqualDiff(conflicts_s[4], "Conflict: can't delete oz because it"
478
                                         " is not empty.  Not deleting.")
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
479
        self.assertEqual(conflicts_s[5], 'Conflict because oz is not'
480
                                         ' versioned, but has versioned'
481
                                         ' children.  Versioned directory.')
482
        self.assertEqual(conflicts_s[6], 'Conflict moving oz/emeraldcity into'
1534.7.171 by Aaron Bentley
Implemented stringifying filesystem conflicts
483
                                         ' oz/emeraldcity.  Cancelled move.')
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
484
1534.7.62 by Aaron Bentley
Fixed moving versioned directories
485
    def test_moving_versioned_directories(self):
486
        create, root = self.get_transform()
487
        kansas = create.new_directory('kansas', root, 'kansas-id')
488
        create.new_directory('house', kansas, 'house-id')
489
        create.new_directory('oz', root, 'oz-id')
490
        create.apply()
491
        cyclone, root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
492
        oz = cyclone.trans_id_tree_file_id('oz-id')
493
        house = cyclone.trans_id_tree_file_id('house-id')
1534.7.62 by Aaron Bentley
Fixed moving versioned directories
494
        cyclone.adjust_path('house', oz, house)
495
        cyclone.apply()
1534.7.66 by Aaron Bentley
Ensured we don't accidentally move the root directory
496
497
    def test_moving_root(self):
1534.7.68 by Aaron Bentley
Got semi-reasonable root directory renaming working
498
        create, root = self.get_transform()
499
        fun = create.new_directory('fun', root, 'fun-id')
500
        create.new_directory('sun', root, 'sun-id')
501
        create.new_directory('moon', root, 'moon')
502
        create.apply()
1534.7.66 by Aaron Bentley
Ensured we don't accidentally move the root directory
503
        transform, root = self.get_transform()
1534.7.68 by Aaron Bentley
Got semi-reasonable root directory renaming working
504
        transform.adjust_root_path('oldroot', fun)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
505
        new_root=transform.trans_id_tree_path('')
1534.7.69 by Aaron Bentley
Got real root moves working
506
        transform.version_file('new-root', new_root)
1534.7.68 by Aaron Bentley
Got semi-reasonable root directory renaming working
507
        transform.apply()
1534.7.93 by Aaron Bentley
Added text merge test
508
1534.7.114 by Aaron Bentley
Added file renaming test case
509
    def test_renames(self):
510
        create, root = self.get_transform()
511
        old = create.new_directory('old-parent', root, 'old-id')
512
        intermediate = create.new_directory('intermediate', old, 'im-id')
513
        myfile = create.new_file('myfile', intermediate, 'myfile-text',
514
                                 'myfile-id')
515
        create.apply()
516
        rename, root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
517
        old = rename.trans_id_file_id('old-id')
1534.7.114 by Aaron Bentley
Added file renaming test case
518
        rename.adjust_path('new', root, old)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
519
        myfile = rename.trans_id_file_id('myfile-id')
1534.7.114 by Aaron Bentley
Added file renaming test case
520
        rename.set_executability(True, myfile)
521
        rename.apply()
522
1534.7.123 by Aaron Bentley
Fixed handling of unversioned files
523
    def test_find_interesting(self):
524
        create, root = self.get_transform()
525
        wt = create._tree
526
        create.new_file('vfile', root, 'myfile-text', 'myfile-id')
527
        create.new_file('uvfile', root, 'othertext')
528
        create.apply()
2255.7.48 by Robert Collins
Deprecated and make work with DirState trees 'transform.find_interesting'.
529
        result = self.applyDeprecated(symbol_versioning.zero_fifteen,
530
            find_interesting, wt, wt, ['vfile'])
531
        self.assertEqual(result, set(['myfile-id']))
1534.7.123 by Aaron Bentley
Fixed handling of unversioned files
532
1740.2.4 by Aaron Bentley
Update transform tests and docs
533
    def test_set_executability_order(self):
534
        """Ensure that executability behaves the same, no matter what order.
535
        
536
        - create file and set executability simultaneously
537
        - create file and set executability afterward
538
        - unsetting the executability of a file whose executability has not been
539
        declared should throw an exception (this may happen when a
540
        merge attempts to create a file with a duplicate ID)
541
        """
542
        transform, root = self.get_transform()
543
        wt = transform._tree
544
        transform.new_file('set_on_creation', root, 'Set on creation', 'soc',
545
                           True)
546
        sac = transform.new_file('set_after_creation', root, 'Set after creation', 'sac')
547
        transform.set_executability(True, sac)
548
        uws = transform.new_file('unset_without_set', root, 'Unset badly', 'uws')
549
        self.assertRaises(KeyError, transform.set_executability, None, uws)
550
        transform.apply()
551
        self.assertTrue(wt.is_executable('soc'))
552
        self.assertTrue(wt.is_executable('sac'))
553
1534.12.2 by Aaron Bentley
Added test for preserving file mode
554
    def test_preserve_mode(self):
555
        """File mode is preserved when replacing content"""
556
        if sys.platform == 'win32':
557
            raise TestSkipped('chmod has no effect on win32')
558
        transform, root = self.get_transform()
559
        transform.new_file('file1', root, 'contents', 'file1-id', True)
560
        transform.apply()
561
        self.assertTrue(self.wt.is_executable('file1-id'))
562
        transform, root = self.get_transform()
563
        file1_id = transform.trans_id_tree_file_id('file1-id')
564
        transform.delete_contents(file1_id)
565
        transform.create_file('contents2', file1_id)
566
        transform.apply()
567
        self.assertTrue(self.wt.is_executable('file1-id'))
568
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
569
    def test__set_mode_stats_correctly(self):
570
        """_set_mode stats to determine file mode."""
571
        if sys.platform == 'win32':
572
            raise TestSkipped('chmod has no effect on win32')
573
574
        stat_paths = []
575
        real_stat = os.stat
576
        def instrumented_stat(path):
577
            stat_paths.append(path)
578
            return real_stat(path)
579
580
        transform, root = self.get_transform()
581
582
        bar1_id = transform.new_file('bar', root, 'bar contents 1\n',
583
                                     file_id='bar-id-1', executable=False)
584
        transform.apply()
585
586
        transform, root = self.get_transform()
587
        bar1_id = transform.trans_id_tree_path('bar')
588
        bar2_id = transform.trans_id_tree_path('bar2')
589
        try:
590
            os.stat = instrumented_stat
591
            transform.create_file('bar2 contents\n', bar2_id, mode_id=bar1_id)
592
        finally:
593
            os.stat = real_stat
594
            transform.finalize()
595
596
        bar1_abspath = self.wt.abspath('bar')
597
        self.assertEqual([bar1_abspath], stat_paths)
598
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
599
    def test_iter_changes(self):
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
600
        self.wt.set_root_id('eert_toor')
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
601
        transform, root = self.get_transform()
602
        transform.new_file('old', root, 'blah', 'id-1', True)
603
        transform.apply()
604
        transform, root = self.get_transform()
605
        try:
606
            self.assertEqual([], list(transform._iter_changes()))
607
            old = transform.trans_id_tree_file_id('id-1')
608
            transform.unversion_file(old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
609
            self.assertEqual([('id-1', ('old', None), False, (True, False),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
610
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
611
                (True, True))], list(transform._iter_changes()))
612
            transform.new_directory('new', root, 'id-1')
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
613
            self.assertEqual([('id-1', ('old', 'new'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
614
                ('eert_toor', 'eert_toor'), ('old', 'new'),
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
615
                ('file', 'directory'),
616
                (True, False))], list(transform._iter_changes()))
617
        finally:
618
            transform.finalize()
619
620
    def test_iter_changes_new(self):
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
621
        self.wt.set_root_id('eert_toor')
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
622
        transform, root = self.get_transform()
623
        transform.new_file('old', root, 'blah')
624
        transform.apply()
625
        transform, root = self.get_transform()
626
        try:
627
            old = transform.trans_id_tree_path('old')
628
            transform.version_file('id-1', old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
629
            self.assertEqual([('id-1', (None, 'old'), False, (False, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
630
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
631
                (False, False))], list(transform._iter_changes()))
632
        finally:
633
            transform.finalize()
634
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
635
    def test_iter_changes_modifications(self):
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
636
        self.wt.set_root_id('eert_toor')
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
637
        transform, root = self.get_transform()
638
        transform.new_file('old', root, 'blah', 'id-1')
639
        transform.new_file('new', root, 'blah')
640
        transform.new_directory('subdir', root, 'subdir-id')
641
        transform.apply()
642
        transform, root = self.get_transform()
643
        try:
644
            old = transform.trans_id_tree_path('old')
645
            subdir = transform.trans_id_tree_file_id('subdir-id')
646
            new = transform.trans_id_tree_path('new')
647
            self.assertEqual([], list(transform._iter_changes()))
648
649
            #content deletion
650
            transform.delete_contents(old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
651
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
652
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', None),
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
653
                (False, False))], list(transform._iter_changes()))
654
655
            #content change
656
            transform.create_file('blah', old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
657
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
658
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
659
                (False, False))], list(transform._iter_changes()))
660
            transform.cancel_deletion(old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
661
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
662
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
663
                (False, False))], list(transform._iter_changes()))
664
            transform.cancel_creation(old)
665
666
            # move file_id to a different file
667
            self.assertEqual([], list(transform._iter_changes()))
668
            transform.unversion_file(old)
669
            transform.version_file('id-1', new)
670
            transform.adjust_path('old', root, new)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
671
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
672
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
673
                (False, False))], list(transform._iter_changes()))
674
            transform.cancel_versioning(new)
675
            transform._removed_id = set()
676
677
            #execute bit
678
            self.assertEqual([], list(transform._iter_changes()))
679
            transform.set_executability(True, old)
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
680
            self.assertEqual([('id-1', ('old', 'old'), False, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
681
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
682
                (False, True))], list(transform._iter_changes()))
683
            transform.set_executability(None, old)
684
685
            # filename
686
            self.assertEqual([], list(transform._iter_changes()))
687
            transform.adjust_path('new', root, old)
688
            transform._new_parent = {}
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
689
            self.assertEqual([('id-1', ('old', 'new'), False, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
690
                ('eert_toor', 'eert_toor'), ('old', 'new'), ('file', 'file'),
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
691
                (False, False))], list(transform._iter_changes()))
692
            transform._new_name = {}
693
694
            # parent directory
695
            self.assertEqual([], list(transform._iter_changes()))
696
            transform.adjust_path('new', subdir, old)
697
            transform._new_name = {}
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
698
            self.assertEqual([('id-1', ('old', 'subdir/old'), False,
2255.2.180 by Martin Pool
merge dirstate
699
                (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.
700
                ('file', 'file'), (False, False))],
701
                list(transform._iter_changes()))
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
702
            transform._new_path = {}
703
704
        finally:
705
            transform.finalize()
706
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
707
    def test_iter_changes_modified_bleed(self):
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
708
        self.wt.set_root_id('eert_toor')
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
709
        """Modified flag should not bleed from one change to another"""
710
        # unfortunately, we have no guarantee that file1 (which is modified)
711
        # will be applied before file2.  And if it's applied after file2, it
712
        # obviously can't bleed into file2's change output.  But for now, it
713
        # works.
714
        transform, root = self.get_transform()
715
        transform.new_file('file1', root, 'blah', 'id-1')
716
        transform.new_file('file2', root, 'blah', 'id-2')
717
        transform.apply()
718
        transform, root = self.get_transform()
719
        try:
720
            transform.delete_contents(transform.trans_id_file_id('id-1'))
721
            transform.set_executability(True,
722
            transform.trans_id_file_id('id-2'))
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
723
            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
724
                ('eert_toor', 'eert_toor'), ('file1', u'file1'),
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
725
                ('file', None), (False, False)),
2255.7.96 by Robert Collins
Change _iter_changes interface to yield both old and new paths.
726
                ('id-2', (u'file2', u'file2'), False, (True, True),
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
727
                ('eert_toor', 'eert_toor'), ('file2', u'file2'),
1551.11.7 by Aaron Bentley
Stop modified flag bleeding into later changes
728
                ('file', 'file'), (False, True))],
729
                list(transform._iter_changes()))
730
        finally:
731
            transform.finalize()
732
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
733
    def test_iter_changes_pointless(self):
734
        """Ensure that no-ops are not treated as modifications"""
2100.3.33 by Aaron Bentley
Handle unique roots in tests for TreeTransform.iter_changes
735
        self.wt.set_root_id('eert_toor')
1551.11.2 by Aaron Bentley
Get kind change detection working for iter_changes
736
        transform, root = self.get_transform()
737
        transform.new_file('old', root, 'blah', 'id-1')
738
        transform.new_directory('subdir', root, 'subdir-id')
739
        transform.apply()
740
        transform, root = self.get_transform()
741
        try:
742
            old = transform.trans_id_tree_path('old')
743
            subdir = transform.trans_id_tree_file_id('subdir-id')
744
            self.assertEqual([], list(transform._iter_changes()))
745
            transform.delete_contents(subdir)
746
            transform.create_directory(subdir)
747
            transform.set_executability(False, old)
748
            transform.unversion_file(old)
749
            transform.version_file('id-1', old)
750
            transform.adjust_path('old', root, old)
751
            self.assertEqual([], list(transform._iter_changes()))
752
        finally:
753
            transform.finalize()
1534.7.93 by Aaron Bentley
Added text merge test
754
755
class TransformGroup(object):
1731.1.33 by Aaron Bentley
Revert no-special-root changes
756
    def __init__(self, dirname, root_id):
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
757
        self.name = dirname
1534.7.93 by Aaron Bentley
Added text merge test
758
        os.mkdir(dirname)
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
759
        self.wt = BzrDir.create_standalone_workingtree(dirname)
1731.1.33 by Aaron Bentley
Revert no-special-root changes
760
        self.wt.set_root_id(root_id)
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
761
        self.b = self.wt.branch
1534.7.93 by Aaron Bentley
Added text merge test
762
        self.tt = TreeTransform(self.wt)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
763
        self.root = self.tt.trans_id_tree_file_id(self.wt.get_root_id())
1534.7.93 by Aaron Bentley
Added text merge test
764
1551.11.1 by Aaron Bentley
Initial work on converting TreeTransform to iter_changes format
765
1534.7.95 by Aaron Bentley
Added more text merge tests
766
def conflict_text(tree, merge):
767
    template = '%s TREE\n%s%s\n%s%s MERGE-SOURCE\n'
768
    return template % ('<' * 7, tree, '=' * 7, merge, '>' * 7)
769
1534.7.93 by Aaron Bentley
Added text merge test
770
771
class TestTransformMerge(TestCaseInTempDir):
772
    def test_text_merge(self):
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
773
        root_id = generate_ids.gen_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
774
        base = TransformGroup("base", root_id)
1534.7.93 by Aaron Bentley
Added text merge test
775
        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
776
        base.tt.new_file('b', base.root, 'b1', 'b')
777
        base.tt.new_file('c', base.root, 'c', 'c')
778
        base.tt.new_file('d', base.root, 'd', 'd')
779
        base.tt.new_file('e', base.root, 'e', 'e')
780
        base.tt.new_file('f', base.root, 'f', 'f')
1534.7.96 by Aaron Bentley
Tested with BASE as directory
781
        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
782
        base.tt.new_directory('h', base.root, 'h')
1534.7.93 by Aaron Bentley
Added text merge test
783
        base.tt.apply()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
784
        other = TransformGroup("other", root_id)
1534.7.93 by Aaron Bentley
Added text merge test
785
        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
786
        other.tt.new_file('b', other.root, 'b2', 'b')
787
        other.tt.new_file('c', other.root, 'c2', 'c')
788
        other.tt.new_file('d', other.root, 'd', 'd')
789
        other.tt.new_file('e', other.root, 'e2', 'e')
790
        other.tt.new_file('f', other.root, 'f', 'f')
1534.7.96 by Aaron Bentley
Tested with BASE as directory
791
        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
792
        other.tt.new_file('h', other.root, 'h\ni\nj\nk\n', 'h')
1534.7.99 by Aaron Bentley
Handle non-existent BASE properly
793
        other.tt.new_file('i', other.root, 'h\ni\nj\nk\n', 'i')
1534.7.93 by Aaron Bentley
Added text merge test
794
        other.tt.apply()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
795
        this = TransformGroup("this", root_id)
1534.7.93 by Aaron Bentley
Added text merge test
796
        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
797
        this.tt.new_file('b', this.root, 'b', 'b')
798
        this.tt.new_file('c', this.root, 'c', 'c')
799
        this.tt.new_file('d', this.root, 'd2', 'd')
800
        this.tt.new_file('e', this.root, 'e2', 'e')
801
        this.tt.new_file('f', this.root, 'f', 'f')
1534.7.96 by Aaron Bentley
Tested with BASE as directory
802
        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
803
        this.tt.new_file('h', this.root, '1\n2\n3\n4\n', 'h')
1534.7.99 by Aaron Bentley
Handle non-existent BASE properly
804
        this.tt.new_file('i', this.root, '1\n2\n3\n4\n', 'i')
1534.7.93 by Aaron Bentley
Added text merge test
805
        this.tt.apply()
806
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1534.7.95 by Aaron Bentley
Added more text merge tests
807
        # textual merge
1534.7.93 by Aaron Bentley
Added text merge test
808
        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
809
        # three-way text conflict
810
        self.assertEqual(this.wt.get_file('b').read(), 
811
                         conflict_text('b', 'b2'))
812
        # OTHER wins
813
        self.assertEqual(this.wt.get_file('c').read(), 'c2')
814
        # THIS wins
815
        self.assertEqual(this.wt.get_file('d').read(), 'd2')
816
        # Ambigious clean merge
817
        self.assertEqual(this.wt.get_file('e').read(), 'e2')
818
        # No change
819
        self.assertEqual(this.wt.get_file('f').read(), 'f')
1534.7.97 by Aaron Bentley
Ensured foo.BASE is a directory if there's a conflict
820
        # Correct correct results when THIS == OTHER 
1534.7.96 by Aaron Bentley
Tested with BASE as directory
821
        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
822
        # Text conflict when THIS & OTHER are text and BASE is dir
823
        self.assertEqual(this.wt.get_file('h').read(), 
824
                         conflict_text('1\n2\n3\n4\n', 'h\ni\nj\nk\n'))
825
        self.assertEqual(this.wt.get_file_byname('h.THIS').read(),
826
                         '1\n2\n3\n4\n')
827
        self.assertEqual(this.wt.get_file_byname('h.OTHER').read(),
828
                         'h\ni\nj\nk\n')
829
        self.assertEqual(file_kind(this.wt.abspath('h.BASE')), 'directory')
1534.7.99 by Aaron Bentley
Handle non-existent BASE properly
830
        self.assertEqual(this.wt.get_file('i').read(), 
831
                         conflict_text('1\n2\n3\n4\n', 'h\ni\nj\nk\n'))
832
        self.assertEqual(this.wt.get_file_byname('i.THIS').read(),
833
                         '1\n2\n3\n4\n')
834
        self.assertEqual(this.wt.get_file_byname('i.OTHER').read(),
835
                         'h\ni\nj\nk\n')
836
        self.assertEqual(os.path.exists(this.wt.abspath('i.BASE')), False)
1534.7.192 by Aaron Bentley
Record hashes produced by merges
837
        modified = ['a', 'b', 'c', 'h', 'i']
838
        merge_modified = this.wt.merge_modified()
839
        self.assertSubset(merge_modified, modified)
840
        self.assertEqual(len(merge_modified), len(modified))
841
        file(this.wt.id2abspath('a'), 'wb').write('booga')
842
        modified.pop(0)
843
        merge_modified = this.wt.merge_modified()
844
        self.assertSubset(merge_modified, modified)
845
        self.assertEqual(len(merge_modified), len(modified))
1558.12.10 by Aaron Bentley
Be robust when merge_hash file_id not in inventory
846
        this.wt.remove('b')
847
        this.wt.revert([])
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
848
849
    def test_file_merge(self):
1534.7.153 by Aaron Bentley
Handled test cases involving symlinks
850
        if not has_symlinks():
851
            raise TestSkipped('Symlinks are not supported on this platform')
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
852
        root_id = generate_ids.gen_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
853
        base = TransformGroup("BASE", root_id)
854
        this = TransformGroup("THIS", root_id)
855
        other = TransformGroup("OTHER", root_id)
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
856
        for tg in this, base, other:
857
            tg.tt.new_directory('a', tg.root, 'a')
858
            tg.tt.new_symlink('b', tg.root, 'b', 'b')
859
            tg.tt.new_file('c', tg.root, 'c', 'c')
860
            tg.tt.new_symlink('d', tg.root, tg.name, 'd')
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
861
        targets = ((base, 'base-e', 'base-f', None, None), 
862
                   (this, 'other-e', 'this-f', 'other-g', 'this-h'), 
863
                   (other, 'other-e', None, 'other-g', 'other-h'))
864
        for tg, e_target, f_target, g_target, h_target in targets:
865
            for link, target in (('e', e_target), ('f', f_target), 
866
                                 ('g', g_target), ('h', h_target)):
867
                if target is not None:
868
                    tg.tt.new_symlink(link, tg.root, target, link)
1534.7.102 by Aaron Bentley
Deleted old pre-conflict contents
869
870
        for tg in this, base, other:
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
871
            tg.tt.apply()
872
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
873
        self.assertIs(os.path.isdir(this.wt.abspath('a')), True)
874
        self.assertIs(os.path.islink(this.wt.abspath('b')), True)
875
        self.assertIs(os.path.isfile(this.wt.abspath('c')), True)
876
        for suffix in ('THIS', 'BASE', 'OTHER'):
877
            self.assertEqual(os.readlink(this.wt.abspath('d.'+suffix)), suffix)
1534.7.102 by Aaron Bentley
Deleted old pre-conflict contents
878
        self.assertIs(os.path.lexists(this.wt.abspath('d')), False)
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
879
        self.assertEqual(this.wt.id2path('d'), 'd.OTHER')
880
        self.assertEqual(this.wt.id2path('f'), 'f.THIS')
1534.7.102 by Aaron Bentley
Deleted old pre-conflict contents
881
        self.assertEqual(os.readlink(this.wt.abspath('e')), 'other-e')
882
        self.assertIs(os.path.lexists(this.wt.abspath('e.THIS')), False)
883
        self.assertIs(os.path.lexists(this.wt.abspath('e.OTHER')), False)
884
        self.assertIs(os.path.lexists(this.wt.abspath('e.BASE')), False)
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
885
        self.assertIs(os.path.lexists(this.wt.abspath('g')), True)
886
        self.assertIs(os.path.lexists(this.wt.abspath('g.BASE')), False)
887
        self.assertIs(os.path.lexists(this.wt.abspath('h')), False)
888
        self.assertIs(os.path.lexists(this.wt.abspath('h.BASE')), False)
889
        self.assertIs(os.path.lexists(this.wt.abspath('h.THIS')), True)
890
        self.assertIs(os.path.lexists(this.wt.abspath('h.OTHER')), True)
1534.7.105 by Aaron Bentley
Got merge with rename working
891
892
    def test_filename_merge(self):
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
893
        root_id = generate_ids.gen_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
894
        base = TransformGroup("BASE", root_id)
895
        this = TransformGroup("THIS", root_id)
896
        other = TransformGroup("OTHER", root_id)
1534.7.105 by Aaron Bentley
Got merge with rename working
897
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, 'a') 
898
                                   for t in [base, this, other]]
899
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, 'b') 
900
                                   for t in [base, this, other]]
901
        base.tt.new_directory('c', base_a, 'c')
902
        this.tt.new_directory('c1', this_a, 'c')
903
        other.tt.new_directory('c', other_b, 'c')
904
905
        base.tt.new_directory('d', base_a, 'd')
906
        this.tt.new_directory('d1', this_b, 'd')
907
        other.tt.new_directory('d', other_a, 'd')
908
909
        base.tt.new_directory('e', base_a, 'e')
910
        this.tt.new_directory('e', this_a, 'e')
911
        other.tt.new_directory('e1', other_b, 'e')
912
913
        base.tt.new_directory('f', base_a, 'f')
914
        this.tt.new_directory('f1', this_b, 'f')
915
        other.tt.new_directory('f1', other_b, 'f')
916
917
        for tg in [this, base, other]:
918
            tg.tt.apply()
919
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1534.7.176 by abentley
Fixed up tests for Windows
920
        self.assertEqual(this.wt.id2path('c'), pathjoin('b/c1'))
921
        self.assertEqual(this.wt.id2path('d'), pathjoin('b/d1'))
922
        self.assertEqual(this.wt.id2path('e'), pathjoin('b/e1'))
923
        self.assertEqual(this.wt.id2path('f'), pathjoin('b/f1'))
1534.7.105 by Aaron Bentley
Got merge with rename working
924
925
    def test_filename_merge_conflicts(self):
2116.4.1 by John Arbash Meinel
Update file and revision id generators.
926
        root_id = generate_ids.gen_root_id()
1731.1.33 by Aaron Bentley
Revert no-special-root changes
927
        base = TransformGroup("BASE", root_id)
928
        this = TransformGroup("THIS", root_id)
929
        other = TransformGroup("OTHER", root_id)
1534.7.105 by Aaron Bentley
Got merge with rename working
930
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, 'a') 
931
                                   for t in [base, this, other]]
932
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, 'b') 
933
                                   for t in [base, this, other]]
934
935
        base.tt.new_file('g', base_a, 'g', 'g')
936
        other.tt.new_file('g1', other_b, 'g1', 'g')
937
938
        base.tt.new_file('h', base_a, 'h', 'h')
939
        this.tt.new_file('h1', this_b, 'h1', 'h')
940
941
        base.tt.new_file('i', base.root, 'i', 'i')
1534.7.153 by Aaron Bentley
Handled test cases involving symlinks
942
        other.tt.new_directory('i1', this_b, 'i')
1534.7.105 by Aaron Bentley
Got merge with rename working
943
944
        for tg in [this, base, other]:
945
            tg.tt.apply()
946
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
947
1534.7.176 by abentley
Fixed up tests for Windows
948
        self.assertEqual(this.wt.id2path('g'), pathjoin('b/g1.OTHER'))
1534.7.105 by Aaron Bentley
Got merge with rename working
949
        self.assertIs(os.path.lexists(this.wt.abspath('b/g1.BASE')), True)
950
        self.assertIs(os.path.lexists(this.wt.abspath('b/g1.THIS')), False)
1534.7.176 by abentley
Fixed up tests for Windows
951
        self.assertEqual(this.wt.id2path('h'), pathjoin('b/h1.THIS'))
1534.7.105 by Aaron Bentley
Got merge with rename working
952
        self.assertIs(os.path.lexists(this.wt.abspath('b/h1.BASE')), True)
953
        self.assertIs(os.path.lexists(this.wt.abspath('b/h1.OTHER')), False)
1534.7.176 by abentley
Fixed up tests for Windows
954
        self.assertEqual(this.wt.id2path('i'), pathjoin('b/i1.OTHER'))
1534.7.183 by Aaron Bentley
Fixed build_tree with symlinks
955
2027.1.1 by John Arbash Meinel
Fix bug #56549, and write a direct test that the right path is being statted
956
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
957
class TestBuildTree(tests.TestCaseWithTransport):
958
1534.7.183 by Aaron Bentley
Fixed build_tree with symlinks
959
    def test_build_tree(self):
960
        if not has_symlinks():
961
            raise TestSkipped('Test requires symlink support')
962
        os.mkdir('a')
963
        a = BzrDir.create_standalone_workingtree('a')
964
        os.mkdir('a/foo')
965
        file('a/foo/bar', 'wb').write('contents')
966
        os.symlink('a/foo/bar', 'a/foo/baz')
967
        a.add(['foo', 'foo/bar', 'foo/baz'])
968
        a.commit('initial commit')
969
        b = BzrDir.create_standalone_workingtree('b')
970
        build_tree(a.basis_tree(), b)
971
        self.assertIs(os.path.isdir('b/foo'), True)
972
        self.assertEqual(file('b/foo/bar', 'rb').read(), "contents")
973
        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
974
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
975
    def test_build_with_references(self):
2255.2.174 by Martin Pool
remove AB1 WorkingTree and experimental-knit3
976
        tree = self.make_branch_and_tree('source', format='experimental-reference-dirstate')
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
977
        subtree = self.make_branch_and_tree('source/subtree', 
2255.2.174 by Martin Pool
remove AB1 WorkingTree and experimental-knit3
978
                                            format='experimental-reference-dirstate')
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
979
        tree.add_reference(subtree)
980
        tree.commit('a revision')
981
        tree.branch.create_checkout('target')
982
        self.failUnlessExists('target')
983
        self.failUnlessExists('target/subtree')
984
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
985
    def test_file_conflict_handling(self):
986
        """Ensure that when building trees, conflict handling is done"""
987
        source = self.make_branch_and_tree('source')
988
        target = self.make_branch_and_tree('target')
989
        self.build_tree(['source/file', 'target/file'])
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
990
        source.add('file', 'new-file')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
991
        source.commit('added file')
992
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
993
        self.assertEqual([DuplicateEntry('Moved existing file to',
994
                          'file.moved', 'file', None, 'new-file')],
995
                         target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
996
        target2 = self.make_branch_and_tree('target2')
997
        target_file = file('target2/file', 'wb')
998
        try:
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
999
            source_file = file('source/file', 'rb')
1000
            try:
1001
                target_file.write(source_file.read())
1002
            finally:
1003
                source_file.close()
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1004
        finally:
1005
            target_file.close()
1006
        build_tree(source.basis_tree(), target2)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1007
        self.assertEqual([], target2.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1008
1009
    def test_symlink_conflict_handling(self):
1010
        """Ensure that when building trees, conflict handling is done"""
1011
        if not has_symlinks():
1012
            raise TestSkipped('Test requires symlink support')
1013
        source = self.make_branch_and_tree('source')
1014
        os.symlink('foo', 'source/symlink')
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1015
        source.add('symlink', 'new-symlink')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1016
        source.commit('added file')
1017
        target = self.make_branch_and_tree('target')
1018
        os.symlink('bar', 'target/symlink')
1019
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1020
        self.assertEqual([DuplicateEntry('Moved existing file to',
1021
            'symlink.moved', 'symlink', None, 'new-symlink')],
1022
            target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1023
        target = self.make_branch_and_tree('target2')
1024
        os.symlink('foo', 'target2/symlink')
1025
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1026
        self.assertEqual([], target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1027
        
1028
    def test_directory_conflict_handling(self):
1029
        """Ensure that when building trees, conflict handling is done"""
1030
        source = self.make_branch_and_tree('source')
1031
        target = self.make_branch_and_tree('target')
1032
        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
1033
        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
1034
        source.commit('added file')
1035
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1036
        self.assertEqual([], target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1037
        self.failUnlessExists('target/dir1/file')
1038
1039
        # Ensure contents are merged
1040
        target = self.make_branch_and_tree('target2')
1041
        self.build_tree(['target2/dir1/', 'target2/dir1/file2'])
1042
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1043
        self.assertEqual([], target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1044
        self.failUnlessExists('target2/dir1/file2')
1045
        self.failUnlessExists('target2/dir1/file')
1046
1047
        # 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
1048
        target = self.make_branch_and_tree('target3')
1049
        self.make_branch('target3/dir1')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1050
        self.build_tree(['target3/dir1/file2'])
1051
        build_tree(source.basis_tree(), target)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1052
        self.failIfExists('target3/dir1/file')
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1053
        self.failUnlessExists('target3/dir1/file2')
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1054
        self.failUnlessExists('target3/dir1.diverted/file')
1055
        self.assertEqual([DuplicateEntry('Diverted to',
1056
            'dir1.diverted', 'dir1', 'new-dir1', None)],
1057
            target.conflicts())
1058
1059
        target = self.make_branch_and_tree('target4')
1060
        self.build_tree(['target4/dir1/'])
1061
        self.make_branch('target4/dir1/file')
1062
        build_tree(source.basis_tree(), target)
1063
        self.failUnlessExists('target4/dir1/file')
1064
        self.assertEqual('directory', file_kind('target4/dir1/file'))
1065
        self.failUnlessExists('target4/dir1/file.diverted')
1066
        self.assertEqual([DuplicateEntry('Diverted to',
1067
            'dir1/file.diverted', 'dir1/file', 'new-file', None)],
1068
            target.conflicts())
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1069
1070
    def test_mixed_conflict_handling(self):
1071
        """Ensure that when building trees, conflict handling is done"""
1072
        source = self.make_branch_and_tree('source')
1073
        target = self.make_branch_and_tree('target')
1074
        self.build_tree(['source/name', 'target/name/'])
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1075
        source.add('name', 'new-name')
1076
        source.commit('added file')
1077
        build_tree(source.basis_tree(), target)
1078
        self.assertEqual([DuplicateEntry('Moved existing file to',
1079
            'name.moved', 'name', None, 'new-name')], target.conflicts())
1080
1081
    def test_raises_in_populated(self):
1082
        source = self.make_branch_and_tree('source')
1083
        self.build_tree(['source/name'])
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1084
        source.add('name')
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
1085
        source.commit('added name')
1086
        target = self.make_branch_and_tree('target')
1087
        self.build_tree(['target/name'])
1088
        target.add('name')
2090.2.1 by Martin Pool
Fix some code which relies on assertions and breaks under python -O
1089
        self.assertRaises(errors.WorkingTreeAlreadyPopulated, 
1090
            build_tree, source.basis_tree(), target)
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1091
1092
1534.10.28 by Aaron Bentley
Use numbered backup files
1093
class MockTransform(object):
1094
1095
    def has_named_child(self, by_parent, parent_id, name):
1096
        for child_id in by_parent[parent_id]:
1097
            if child_id == '0':
1098
                if name == "name~":
1099
                    return True
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
1100
            elif name == "name.~%s~" % child_id:
1534.10.28 by Aaron Bentley
Use numbered backup files
1101
                return True
1102
        return False
1103
1104
class MockEntry(object):
1105
    def __init__(self):
1106
        object.__init__(self)
1107
        self.name = "name"
1108
1109
class TestGetBackupName(TestCase):
1110
    def test_get_backup_name(self):
1111
        tt = MockTransform()
1112
        name = get_backup_name(MockEntry(), {'a':[]}, 'a', tt)
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
1113
        self.assertEqual(name, 'name.~1~')
1114
        name = get_backup_name(MockEntry(), {'a':['1']}, 'a', tt)
1115
        self.assertEqual(name, 'name.~2~')
1534.10.28 by Aaron Bentley
Use numbered backup files
1116
        name = get_backup_name(MockEntry(), {'a':['2']}, 'a', tt)
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
1117
        self.assertEqual(name, 'name.~1~')
1534.10.28 by Aaron Bentley
Use numbered backup files
1118
        name = get_backup_name(MockEntry(), {'a':['2'], 'b':[]}, 'b', tt)
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
1119
        self.assertEqual(name, 'name.~1~')
1120
        name = get_backup_name(MockEntry(), {'a':['1', '2', '3']}, 'a', tt)
1121
        self.assertEqual(name, 'name.~4~')