~bzr-pqm/bzr/bzr.dev

1534.7.106 by Aaron Bentley
Cleaned up imports, added copyright statements
1
# Copyright (C) 2006 Canonical Ltd
2
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.
7
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.
12
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
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
18
19
from bzrlib.bzrdir import BzrDir
1534.7.32 by Aaron Bentley
Got conflict handling working when conflicts involve existing files
20
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
1534.7.162 by Aaron Bentley
Handle failures creating/deleting the Limbo directory
21
                           ReusingTransform, CantMoveRoot, NotVersionedError,
22
                           ExistingLimbo, ImmortalLimbo, LockError)
1534.7.176 by abentley
Fixed up tests for Windows
23
from bzrlib.osutils import file_kind, has_symlinks, pathjoin
1534.7.140 by Aaron Bentley
Moved the merge stuff into merge.py
24
from bzrlib.merge import Merge3Merger
1534.7.106 by Aaron Bentley
Cleaned up imports, added copyright statements
25
from bzrlib.tests import TestCaseInTempDir, TestSkipped
26
from bzrlib.transform import (TreeTransform, ROOT_PARENT, FinalPaths, 
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
27
                              resolve_conflicts, cook_conflicts, 
1534.7.171 by Aaron Bentley
Implemented stringifying filesystem conflicts
28
                              conflicts_strings, find_interesting)
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
29
30
class TestTreeTransform(TestCaseInTempDir):
1534.7.59 by Aaron Bentley
Simplified tests
31
    def setUp(self):
32
        super(TestTreeTransform, self).setUp()
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
33
        self.wt = BzrDir.create_standalone_workingtree('.')
1534.7.161 by Aaron Bentley
Used appropriate control_files
34
        os.chdir('..')
1534.7.59 by Aaron Bentley
Simplified tests
35
36
    def get_transform(self):
37
        transform = TreeTransform(self.wt)
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
38
        #self.addCleanup(transform.finalize)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
39
        return transform, transform.trans_id_tree_file_id(self.wt.get_root_id())
1534.7.59 by Aaron Bentley
Simplified tests
40
1534.7.162 by Aaron Bentley
Handle failures creating/deleting the Limbo directory
41
    def test_existing_limbo(self):
42
        limbo_name = self.wt._control_files.controlfilename('limbo')
43
        transform, root = self.get_transform()
1534.7.176 by abentley
Fixed up tests for Windows
44
        os.mkdir(pathjoin(limbo_name, 'hehe'))
1534.7.162 by Aaron Bentley
Handle failures creating/deleting the Limbo directory
45
        self.assertRaises(ImmortalLimbo, transform.apply)
46
        self.assertRaises(LockError, self.wt.unlock)
47
        self.assertRaises(ExistingLimbo, self.get_transform)
48
        self.assertRaises(LockError, self.wt.unlock)
1534.7.176 by abentley
Fixed up tests for Windows
49
        os.rmdir(pathjoin(limbo_name, 'hehe'))
1534.7.162 by Aaron Bentley
Handle failures creating/deleting the Limbo directory
50
        os.rmdir(limbo_name)
51
        transform, root = self.get_transform()
52
        transform.apply()
1534.7.59 by Aaron Bentley
Simplified tests
53
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
54
    def test_build(self):
1534.7.59 by Aaron Bentley
Simplified tests
55
        transform, root = self.get_transform() 
56
        self.assertIs(transform.get_tree_parent(root), ROOT_PARENT)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
57
        imaginary_id = transform.trans_id_tree_path('imaginary')
1534.7.59 by Aaron Bentley
Simplified tests
58
        self.assertEqual(transform.get_tree_parent(imaginary_id), root)
59
        self.assertEqual(transform.final_kind(root), 'directory')
60
        self.assertEqual(transform.final_file_id(root), self.wt.get_root_id())
61
        trans_id = transform.create_path('name', root)
62
        self.assertIs(transform.final_file_id(trans_id), None)
63
        self.assertRaises(NoSuchFile, transform.final_kind, trans_id)
64
        transform.create_file('contents', trans_id)
65
        transform.set_executability(True, trans_id)
66
        transform.version_file('my_pretties', trans_id)
67
        self.assertRaises(DuplicateKey, transform.version_file,
68
                          'my_pretties', trans_id)
69
        self.assertEqual(transform.final_file_id(trans_id), 'my_pretties')
70
        self.assertEqual(transform.final_parent(trans_id), root)
71
        self.assertIs(transform.final_parent(root), ROOT_PARENT)
72
        self.assertIs(transform.get_tree_parent(root), ROOT_PARENT)
73
        oz_id = transform.create_path('oz', root)
74
        transform.create_directory(oz_id)
75
        transform.version_file('ozzie', oz_id)
76
        trans_id2 = transform.create_path('name2', root)
77
        transform.create_file('contents', trans_id2)
78
        transform.set_executability(False, trans_id2)
79
        transform.version_file('my_pretties2', trans_id2)
80
        transform.apply()
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
81
        self.assertEqual('contents', self.wt.get_file_byname('name').read())
1534.7.59 by Aaron Bentley
Simplified tests
82
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
83
        self.assertIs(self.wt.is_executable('my_pretties'), True)
84
        self.assertIs(self.wt.is_executable('my_pretties2'), False)
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
85
        self.assertEqual('directory', file_kind(self.wt.abspath('oz')))
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
86
        # is it safe to finalize repeatedly?
87
        transform.finalize()
1534.7.59 by Aaron Bentley
Simplified tests
88
        transform.finalize()
1534.7.2 by Aaron Bentley
Added convenience function
89
90
    def test_convenience(self):
1534.7.59 by Aaron Bentley
Simplified tests
91
        transform, root = self.get_transform()
92
        trans_id = transform.new_file('name', root, 'contents', 
93
                                      'my_pretties', True)
94
        oz = transform.new_directory('oz', root, 'oz-id')
95
        dorothy = transform.new_directory('dorothy', oz, 'dorothy-id')
96
        toto = transform.new_file('toto', dorothy, 'toto-contents', 
97
                                  'toto-id', False)
98
99
        self.assertEqual(len(transform.find_conflicts()), 0)
100
        transform.apply()
101
        self.assertRaises(ReusingTransform, transform.find_conflicts)
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
102
        self.assertEqual('contents', file(self.wt.abspath('name')).read())
1534.7.59 by Aaron Bentley
Simplified tests
103
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
104
        self.assertIs(self.wt.is_executable('my_pretties'), True)
105
        self.assertEqual(self.wt.path2id('oz'), 'oz-id')
106
        self.assertEqual(self.wt.path2id('oz/dorothy'), 'dorothy-id')
107
        self.assertEqual(self.wt.path2id('oz/dorothy/toto'), 'toto-id')
108
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
109
        self.assertEqual('toto-contents', 
110
                         self.wt.get_file_byname('oz/dorothy/toto').read())
1534.7.59 by Aaron Bentley
Simplified tests
111
        self.assertIs(self.wt.is_executable('toto-id'), False)
1534.7.6 by Aaron Bentley
Added conflict handling
112
113
    def test_conflicts(self):
1534.7.59 by Aaron Bentley
Simplified tests
114
        transform, root = self.get_transform()
115
        trans_id = transform.new_file('name', root, 'contents', 
116
                                      'my_pretties')
117
        self.assertEqual(len(transform.find_conflicts()), 0)
118
        trans_id2 = transform.new_file('name', root, 'Crontents', 'toto')
119
        self.assertEqual(transform.find_conflicts(), 
120
                         [('duplicate', trans_id, trans_id2, 'name')])
121
        self.assertRaises(MalformedTransform, transform.apply)
122
        transform.adjust_path('name', trans_id, trans_id2)
123
        self.assertEqual(transform.find_conflicts(), 
124
                         [('non-directory parent', trans_id)])
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
125
        tinman_id = transform.trans_id_tree_path('tinman')
1534.7.59 by Aaron Bentley
Simplified tests
126
        transform.adjust_path('name', tinman_id, trans_id2)
127
        self.assertEqual(transform.find_conflicts(), 
128
                         [('unversioned parent', tinman_id), 
129
                          ('missing parent', tinman_id)])
130
        lion_id = transform.create_path('lion', root)
131
        self.assertEqual(transform.find_conflicts(), 
132
                         [('unversioned parent', tinman_id), 
133
                          ('missing parent', tinman_id)])
134
        transform.adjust_path('name', lion_id, trans_id2)
135
        self.assertEqual(transform.find_conflicts(), 
136
                         [('unversioned parent', lion_id),
137
                          ('missing parent', lion_id)])
138
        transform.version_file("Courage", lion_id)
139
        self.assertEqual(transform.find_conflicts(), 
140
                         [('missing parent', lion_id), 
141
                          ('versioning no contents', lion_id)])
142
        transform.adjust_path('name2', root, trans_id2)
143
        self.assertEqual(transform.find_conflicts(), 
144
                         [('versioning no contents', lion_id)])
145
        transform.create_file('Contents, okay?', lion_id)
146
        transform.adjust_path('name2', trans_id2, trans_id2)
147
        self.assertEqual(transform.find_conflicts(), 
148
                         [('parent loop', trans_id2), 
149
                          ('non-directory parent', trans_id2)])
150
        transform.adjust_path('name2', root, trans_id2)
151
        oz_id = transform.new_directory('oz', root)
152
        transform.set_executability(True, oz_id)
153
        self.assertEqual(transform.find_conflicts(), 
154
                         [('unversioned executability', oz_id)])
155
        transform.version_file('oz-id', oz_id)
156
        self.assertEqual(transform.find_conflicts(), 
157
                         [('non-file executability', oz_id)])
158
        transform.set_executability(None, oz_id)
1534.7.71 by abentley
All tests pass under Windows
159
        tip_id = transform.new_file('tip', oz_id, 'ozma', 'tip-id')
1534.7.59 by Aaron Bentley
Simplified tests
160
        transform.apply()
161
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
162
        self.assertEqual('contents', file(self.wt.abspath('name')).read())
163
        transform2, root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
164
        oz_id = transform2.trans_id_tree_file_id('oz-id')
1534.7.59 by Aaron Bentley
Simplified tests
165
        newtip = transform2.new_file('tip', oz_id, 'other', 'tip-id')
166
        result = transform2.find_conflicts()
1534.7.135 by Aaron Bentley
Fixed deletion handling
167
        fp = FinalPaths(transform2)
1534.7.59 by Aaron Bentley
Simplified tests
168
        self.assert_('oz/tip' in transform2._tree_path_ids)
1534.7.176 by abentley
Fixed up tests for Windows
169
        self.assertEqual(fp.get_path(newtip), pathjoin('oz', 'tip'))
1534.7.59 by Aaron Bentley
Simplified tests
170
        self.assertEqual(len(result), 2)
171
        self.assertEqual((result[0][0], result[0][1]), 
172
                         ('duplicate', newtip))
173
        self.assertEqual((result[1][0], result[1][2]), 
174
                         ('duplicate id', newtip))
1534.7.73 by Aaron Bentley
Changed model again. Now iterator is used immediately.
175
        transform2.finalize()
1534.7.59 by Aaron Bentley
Simplified tests
176
        transform3 = TreeTransform(self.wt)
177
        self.addCleanup(transform3.finalize)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
178
        oz_id = transform3.trans_id_tree_file_id('oz-id')
1534.7.59 by Aaron Bentley
Simplified tests
179
        transform3.delete_contents(oz_id)
180
        self.assertEqual(transform3.find_conflicts(), 
181
                         [('missing parent', oz_id)])
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
182
        root_id = transform3.trans_id_tree_file_id('TREE_ROOT')
183
        tip_id = transform3.trans_id_tree_file_id('tip-id')
1534.7.59 by Aaron Bentley
Simplified tests
184
        transform3.adjust_path('tip', root_id, tip_id)
185
        transform3.apply()
1534.7.36 by Aaron Bentley
Added rename tests
186
1534.7.46 by Aaron Bentley
Ensured a conflict when parents of versioned files are unversioned
187
    def test_unversioning(self):
1534.7.59 by Aaron Bentley
Simplified tests
188
        create_tree, root = self.get_transform()
189
        parent_id = create_tree.new_directory('parent', root, 'parent-id')
190
        create_tree.new_file('child', parent_id, 'child', 'child-id')
191
        create_tree.apply()
192
        unversion = TreeTransform(self.wt)
193
        self.addCleanup(unversion.finalize)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
194
        parent = unversion.trans_id_tree_path('parent')
1534.7.59 by Aaron Bentley
Simplified tests
195
        unversion.unversion_file(parent)
196
        self.assertEqual(unversion.find_conflicts(), 
197
                         [('unversioned parent', parent_id)])
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
198
        file_id = unversion.trans_id_tree_file_id('child-id')
1534.7.59 by Aaron Bentley
Simplified tests
199
        unversion.unversion_file(file_id)
200
        unversion.apply()
1534.7.46 by Aaron Bentley
Ensured a conflict when parents of versioned files are unversioned
201
1534.7.36 by Aaron Bentley
Added rename tests
202
    def test_name_invariants(self):
1534.7.59 by Aaron Bentley
Simplified tests
203
        create_tree, root = self.get_transform()
204
        # prepare tree
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
205
        root = create_tree.trans_id_tree_file_id('TREE_ROOT')
1534.7.59 by Aaron Bentley
Simplified tests
206
        create_tree.new_file('name1', root, 'hello1', 'name1')
207
        create_tree.new_file('name2', root, 'hello2', 'name2')
208
        ddir = create_tree.new_directory('dying_directory', root, 'ddir')
209
        create_tree.new_file('dying_file', ddir, 'goodbye1', 'dfile')
210
        create_tree.new_file('moving_file', ddir, 'later1', 'mfile')
211
        create_tree.new_file('moving_file2', root, 'later2', 'mfile2')
212
        create_tree.apply()
213
214
        mangle_tree,root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
215
        root = mangle_tree.trans_id_tree_file_id('TREE_ROOT')
1534.7.59 by Aaron Bentley
Simplified tests
216
        #swap names
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
217
        name1 = mangle_tree.trans_id_tree_file_id('name1')
218
        name2 = mangle_tree.trans_id_tree_file_id('name2')
1534.7.59 by Aaron Bentley
Simplified tests
219
        mangle_tree.adjust_path('name2', root, name1)
220
        mangle_tree.adjust_path('name1', root, name2)
221
222
        #tests for deleting parent directories 
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
223
        ddir = mangle_tree.trans_id_tree_file_id('ddir')
1534.7.59 by Aaron Bentley
Simplified tests
224
        mangle_tree.delete_contents(ddir)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
225
        dfile = mangle_tree.trans_id_tree_file_id('dfile')
1534.7.59 by Aaron Bentley
Simplified tests
226
        mangle_tree.delete_versioned(dfile)
227
        mangle_tree.unversion_file(dfile)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
228
        mfile = mangle_tree.trans_id_tree_file_id('mfile')
1534.7.59 by Aaron Bentley
Simplified tests
229
        mangle_tree.adjust_path('mfile', root, mfile)
230
231
        #tests for adding parent directories
232
        newdir = mangle_tree.new_directory('new_directory', root, 'newdir')
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
233
        mfile2 = mangle_tree.trans_id_tree_file_id('mfile2')
1534.7.59 by Aaron Bentley
Simplified tests
234
        mangle_tree.adjust_path('mfile2', newdir, mfile2)
235
        mangle_tree.new_file('newfile', newdir, 'hello3', 'dfile')
236
        self.assertEqual(mangle_tree.final_file_id(mfile2), 'mfile2')
237
        self.assertEqual(mangle_tree.final_parent(mfile2), newdir)
238
        self.assertEqual(mangle_tree.final_file_id(mfile2), 'mfile2')
239
        mangle_tree.apply()
240
        self.assertEqual(file(self.wt.abspath('name1')).read(), 'hello2')
241
        self.assertEqual(file(self.wt.abspath('name2')).read(), 'hello1')
1534.7.176 by abentley
Fixed up tests for Windows
242
        mfile2_path = self.wt.abspath(pathjoin('new_directory','mfile2'))
1534.7.41 by Aaron Bentley
Got inventory ID movement working
243
        self.assertEqual(mangle_tree.final_parent(mfile2), newdir)
1534.7.38 by Aaron Bentley
Tested adding paths
244
        self.assertEqual(file(mfile2_path).read(), 'later2')
1534.7.59 by Aaron Bentley
Simplified tests
245
        self.assertEqual(self.wt.id2path('mfile2'), 'new_directory/mfile2')
246
        self.assertEqual(self.wt.path2id('new_directory/mfile2'), 'mfile2')
1534.7.176 by abentley
Fixed up tests for Windows
247
        newfile_path = self.wt.abspath(pathjoin('new_directory','newfile'))
1534.7.38 by Aaron Bentley
Tested adding paths
248
        self.assertEqual(file(newfile_path).read(), 'hello3')
1534.7.59 by Aaron Bentley
Simplified tests
249
        self.assertEqual(self.wt.path2id('dying_directory'), 'ddir')
250
        self.assertIs(self.wt.path2id('dying_directory/dying_file'), None)
1534.7.176 by abentley
Fixed up tests for Windows
251
        mfile2_path = self.wt.abspath(pathjoin('new_directory','mfile2'))
1534.7.43 by abentley
Fixed some Windows bugs, introduced a conflicts bug
252
1534.7.150 by Aaron Bentley
Handled simultaneous renames of parent and child better
253
    def test_both_rename(self):
254
        create_tree,root = self.get_transform()
255
        newdir = create_tree.new_directory('selftest', root, 'selftest-id')
256
        create_tree.new_file('blackbox.py', newdir, 'hello1', 'blackbox-id')
257
        create_tree.apply()        
258
        mangle_tree,root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
259
        selftest = mangle_tree.trans_id_tree_file_id('selftest-id')
260
        blackbox = mangle_tree.trans_id_tree_file_id('blackbox-id')
1534.7.150 by Aaron Bentley
Handled simultaneous renames of parent and child better
261
        mangle_tree.adjust_path('test', root, selftest)
262
        mangle_tree.adjust_path('test_too_much', root, selftest)
263
        mangle_tree.set_executability(True, blackbox)
264
        mangle_tree.apply()
265
266
    def test_both_rename2(self):
267
        create_tree,root = self.get_transform()
268
        bzrlib = create_tree.new_directory('bzrlib', root, 'bzrlib-id')
269
        tests = create_tree.new_directory('tests', bzrlib, 'tests-id')
270
        blackbox = create_tree.new_directory('blackbox', tests, 'blackbox-id')
271
        create_tree.new_file('test_too_much.py', blackbox, 'hello1', 
272
                             'test_too_much-id')
273
        create_tree.apply()        
274
        mangle_tree,root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
275
        bzrlib = mangle_tree.trans_id_tree_file_id('bzrlib-id')
276
        tests = mangle_tree.trans_id_tree_file_id('tests-id')
277
        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
278
        mangle_tree.adjust_path('selftest', bzrlib, tests)
279
        mangle_tree.adjust_path('blackbox.py', tests, test_too_much) 
280
        mangle_tree.set_executability(True, test_too_much)
281
        mangle_tree.apply()
282
283
    def test_both_rename3(self):
284
        create_tree,root = self.get_transform()
285
        tests = create_tree.new_directory('tests', root, 'tests-id')
286
        create_tree.new_file('test_too_much.py', tests, 'hello1', 
287
                             'test_too_much-id')
288
        create_tree.apply()        
289
        mangle_tree,root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
290
        tests = mangle_tree.trans_id_tree_file_id('tests-id')
291
        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
292
        mangle_tree.adjust_path('selftest', root, tests)
293
        mangle_tree.adjust_path('blackbox.py', tests, test_too_much) 
294
        mangle_tree.set_executability(True, test_too_much)
295
        mangle_tree.apply()
296
1534.7.48 by Aaron Bentley
Ensured we can move/rename dangling inventory entries
297
    def test_move_dangling_ie(self):
1534.7.59 by Aaron Bentley
Simplified tests
298
        create_tree, root = self.get_transform()
299
        # prepare tree
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
300
        root = create_tree.trans_id_tree_file_id('TREE_ROOT')
1534.7.59 by Aaron Bentley
Simplified tests
301
        create_tree.new_file('name1', root, 'hello1', 'name1')
302
        create_tree.apply()
303
        delete_contents, root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
304
        file = delete_contents.trans_id_tree_file_id('name1')
1534.7.59 by Aaron Bentley
Simplified tests
305
        delete_contents.delete_contents(file)
306
        delete_contents.apply()
307
        move_id, root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
308
        name1 = move_id.trans_id_tree_file_id('name1')
1534.7.59 by Aaron Bentley
Simplified tests
309
        newdir = move_id.new_directory('dir', root, 'newdir')
310
        move_id.adjust_path('name2', newdir, name1)
311
        move_id.apply()
1534.7.48 by Aaron Bentley
Ensured we can move/rename dangling inventory entries
312
        
1534.7.50 by Aaron Bentley
Detect duplicate inventory ids
313
    def test_replace_dangling_ie(self):
1534.7.59 by Aaron Bentley
Simplified tests
314
        create_tree, root = self.get_transform()
315
        # prepare tree
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
316
        root = create_tree.trans_id_tree_file_id('TREE_ROOT')
1534.7.59 by Aaron Bentley
Simplified tests
317
        create_tree.new_file('name1', root, 'hello1', 'name1')
318
        create_tree.apply()
319
        delete_contents = TreeTransform(self.wt)
320
        self.addCleanup(delete_contents.finalize)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
321
        file = delete_contents.trans_id_tree_file_id('name1')
1534.7.59 by Aaron Bentley
Simplified tests
322
        delete_contents.delete_contents(file)
323
        delete_contents.apply()
324
        delete_contents.finalize()
325
        replace = TreeTransform(self.wt)
326
        self.addCleanup(replace.finalize)
327
        name2 = replace.new_file('name2', root, 'hello2', 'name1')
328
        conflicts = replace.find_conflicts()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
329
        name1 = replace.trans_id_tree_file_id('name1')
1534.7.59 by Aaron Bentley
Simplified tests
330
        self.assertEqual(conflicts, [('duplicate id', name1, name2)])
331
        resolve_conflicts(replace)
332
        replace.apply()
1534.7.48 by Aaron Bentley
Ensured we can move/rename dangling inventory entries
333
1534.7.43 by abentley
Fixed some Windows bugs, introduced a conflicts bug
334
    def test_symlinks(self):
1534.7.45 by Aaron Bentley
Skipped symlink test more correctly
335
        if not has_symlinks():
336
            raise TestSkipped('Symlinks are not supported on this platform')
1534.7.59 by Aaron Bentley
Simplified tests
337
        transform,root = self.get_transform()
338
        oz_id = transform.new_directory('oz', root, 'oz-id')
339
        wizard = transform.new_symlink('wizard', oz_id, 'wizard-target', 
340
                                       'wizard-id')
341
        wiz_id = transform.create_path('wizard2', oz_id)
342
        transform.create_symlink('behind_curtain', wiz_id)
343
        transform.version_file('wiz-id2', wiz_id)            
1534.7.71 by abentley
All tests pass under Windows
344
        transform.set_executability(True, wiz_id)
345
        self.assertEqual(transform.find_conflicts(), 
346
                         [('non-file executability', wiz_id)])
347
        transform.set_executability(None, wiz_id)
1534.7.59 by Aaron Bentley
Simplified tests
348
        transform.apply()
349
        self.assertEqual(self.wt.path2id('oz/wizard'), 'wizard-id')
1534.7.100 by Aaron Bentley
Fixed path-relative test cases
350
        self.assertEqual(file_kind(self.wt.abspath('oz/wizard')), 'symlink')
351
        self.assertEqual(os.readlink(self.wt.abspath('oz/wizard2')), 
352
                         'behind_curtain')
353
        self.assertEqual(os.readlink(self.wt.abspath('oz/wizard')),
354
                         'wizard-target')
1534.7.60 by Aaron Bentley
Tested existing conflict resolution functionality
355
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
356
357
    def get_conflicted(self):
1534.7.60 by Aaron Bentley
Tested existing conflict resolution functionality
358
        create,root = self.get_transform()
359
        create.new_file('dorothy', root, 'dorothy', 'dorothy-id')
1534.7.61 by Aaron Bentley
Handled parent loops, missing parents, unversioned parents
360
        oz = create.new_directory('oz', root, 'oz-id')
361
        create.new_directory('emeraldcity', oz, 'emerald-id')
1534.7.60 by Aaron Bentley
Tested existing conflict resolution functionality
362
        create.apply()
363
        conflicts,root = self.get_transform()
1534.7.65 by Aaron Bentley
Text cleaup/docs
364
        # set up duplicate entry, duplicate id
1534.7.60 by Aaron Bentley
Tested existing conflict resolution functionality
365
        new_dorothy = conflicts.new_file('dorothy', root, 'dorothy', 
366
                                         'dorothy-id')
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
367
        old_dorothy = conflicts.trans_id_tree_file_id('dorothy-id')
368
        oz = conflicts.trans_id_tree_file_id('oz-id')
1534.7.65 by Aaron Bentley
Text cleaup/docs
369
        # set up missing, unversioned parent
370
        conflicts.delete_versioned(oz)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
371
        emerald = conflicts.trans_id_tree_file_id('emerald-id')
1534.7.65 by Aaron Bentley
Text cleaup/docs
372
        # set up parent loop
1534.7.61 by Aaron Bentley
Handled parent loops, missing parents, unversioned parents
373
        conflicts.adjust_path('emeraldcity', emerald, emerald)
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
374
        return conflicts, emerald, oz, old_dorothy, new_dorothy
375
376
    def test_conflict_resolution(self):
377
        conflicts, emerald, oz, old_dorothy, new_dorothy =\
378
            self.get_conflicted()
1534.7.60 by Aaron Bentley
Tested existing conflict resolution functionality
379
        resolve_conflicts(conflicts)
380
        self.assertEqual(conflicts.final_name(old_dorothy), 'dorothy.moved')
381
        self.assertIs(conflicts.final_file_id(old_dorothy), None)
382
        self.assertEqual(conflicts.final_name(new_dorothy), 'dorothy')
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
383
        self.assertEqual(conflicts.final_file_id(new_dorothy), 'dorothy-id')
1534.7.64 by Aaron Bentley
Extra testing
384
        self.assertEqual(conflicts.final_parent(emerald), oz)
1534.7.63 by Aaron Bentley
Ensure transform can be applied after resolution
385
        conflicts.apply()
1534.7.62 by Aaron Bentley
Fixed moving versioned directories
386
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
387
    def test_cook_conflicts(self):
388
        tt, emerald, oz, old_dorothy, new_dorothy = self.get_conflicted()
389
        raw_conflicts = resolve_conflicts(tt)
390
        cooked_conflicts = cook_conflicts(raw_conflicts, tt)
1534.7.171 by Aaron Bentley
Implemented stringifying filesystem conflicts
391
        duplicate = ('duplicate', 'Moved existing file to', 'dorothy.moved', 
392
                     None, 'dorothy', 'dorothy-id')
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
393
        self.assertEqual(cooked_conflicts[0], duplicate)
394
        duplicate_id = ('duplicate id', 'Unversioned existing file', 
395
                        'dorothy.moved', None, 'dorothy', 'dorothy-id')
396
        self.assertEqual(cooked_conflicts[1], duplicate_id)
397
        missing_parent = ('missing parent', 'Not deleting', 'oz', 'oz-id')
398
        self.assertEqual(cooked_conflicts[2], missing_parent)
399
        unversioned_parent = ('unversioned parent', 
1534.7.171 by Aaron Bentley
Implemented stringifying filesystem conflicts
400
                              'Versioned directory', 'oz', 'oz-id')
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
401
        self.assertEqual(cooked_conflicts[3], unversioned_parent)
402
        parent_loop = ('parent loop', 'Cancelled move', 'oz/emeraldcity', 
403
                       'emerald-id', 'oz/emeraldcity', 'emerald-id')
404
        self.assertEqual(cooked_conflicts[4], parent_loop)
405
        self.assertEqual(len(cooked_conflicts), 5)
406
        tt.finalize()
407
408
    def test_string_conflicts(self):
409
        tt, emerald, oz, old_dorothy, new_dorothy = self.get_conflicted()
410
        raw_conflicts = resolve_conflicts(tt)
411
        cooked_conflicts = cook_conflicts(raw_conflicts, tt)
412
        tt.finalize()
1534.7.171 by Aaron Bentley
Implemented stringifying filesystem conflicts
413
        conflicts_s = list(conflicts_strings(cooked_conflicts))
414
        self.assertEqual(len(cooked_conflicts), len(conflicts_s))
415
        self.assertEqual(conflicts_s[0], 'Conflict adding file dorothy.  '
416
                                         'Moved existing file to '
417
                                         'dorothy.moved.')
418
        self.assertEqual(conflicts_s[1], 'Conflict adding id to dorothy.  '
419
                                         'Unversioned existing file '
420
                                         'dorothy.moved.')
421
        self.assertEqual(conflicts_s[2], 'Conflict adding files to oz.  '
422
                                         'Not deleting.')
423
        self.assertEqual(conflicts_s[3], 'Conflict adding versioned files to '
424
                                         'oz.  Versioned directory.')
425
        self.assertEqual(conflicts_s[4], 'Conflict moving oz/emeraldcity into'
426
                                         ' oz/emeraldcity.  Cancelled move.')
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
427
1534.7.62 by Aaron Bentley
Fixed moving versioned directories
428
    def test_moving_versioned_directories(self):
429
        create, root = self.get_transform()
430
        kansas = create.new_directory('kansas', root, 'kansas-id')
431
        create.new_directory('house', kansas, 'house-id')
432
        create.new_directory('oz', root, 'oz-id')
433
        create.apply()
434
        cyclone, root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
435
        oz = cyclone.trans_id_tree_file_id('oz-id')
436
        house = cyclone.trans_id_tree_file_id('house-id')
1534.7.62 by Aaron Bentley
Fixed moving versioned directories
437
        cyclone.adjust_path('house', oz, house)
438
        cyclone.apply()
1534.7.66 by Aaron Bentley
Ensured we don't accidentally move the root directory
439
440
    def test_moving_root(self):
1534.7.68 by Aaron Bentley
Got semi-reasonable root directory renaming working
441
        create, root = self.get_transform()
442
        fun = create.new_directory('fun', root, 'fun-id')
443
        create.new_directory('sun', root, 'sun-id')
444
        create.new_directory('moon', root, 'moon')
445
        create.apply()
1534.7.66 by Aaron Bentley
Ensured we don't accidentally move the root directory
446
        transform, root = self.get_transform()
1534.7.68 by Aaron Bentley
Got semi-reasonable root directory renaming working
447
        transform.adjust_root_path('oldroot', fun)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
448
        new_root=transform.trans_id_tree_path('')
1534.7.69 by Aaron Bentley
Got real root moves working
449
        transform.version_file('new-root', new_root)
1534.7.68 by Aaron Bentley
Got semi-reasonable root directory renaming working
450
        transform.apply()
1534.7.93 by Aaron Bentley
Added text merge test
451
1534.7.114 by Aaron Bentley
Added file renaming test case
452
    def test_renames(self):
453
        create, root = self.get_transform()
454
        old = create.new_directory('old-parent', root, 'old-id')
455
        intermediate = create.new_directory('intermediate', old, 'im-id')
456
        myfile = create.new_file('myfile', intermediate, 'myfile-text',
457
                                 'myfile-id')
458
        create.apply()
459
        rename, root = self.get_transform()
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
460
        old = rename.trans_id_file_id('old-id')
1534.7.114 by Aaron Bentley
Added file renaming test case
461
        rename.adjust_path('new', root, old)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
462
        myfile = rename.trans_id_file_id('myfile-id')
1534.7.114 by Aaron Bentley
Added file renaming test case
463
        rename.set_executability(True, myfile)
464
        rename.apply()
465
1534.7.123 by Aaron Bentley
Fixed handling of unversioned files
466
    def test_find_interesting(self):
467
        create, root = self.get_transform()
468
        wt = create._tree
469
        create.new_file('vfile', root, 'myfile-text', 'myfile-id')
470
        create.new_file('uvfile', root, 'othertext')
471
        create.apply()
472
        self.assertEqual(find_interesting(wt, wt, ['vfile']),
473
                         set(['myfile-id']))
474
        self.assertRaises(NotVersionedError, find_interesting, wt, wt,
475
                          ['uvfile'])
476
1534.7.93 by Aaron Bentley
Added text merge test
477
478
class TransformGroup(object):
479
    def __init__(self, dirname):
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
480
        self.name = dirname
1534.7.93 by Aaron Bentley
Added text merge test
481
        os.mkdir(dirname)
1558.1.3 by Aaron Bentley
Fixed deprecated op use in test suite
482
        self.wt = BzrDir.create_standalone_workingtree(dirname)
483
        self.b = self.wt.branch
1534.7.93 by Aaron Bentley
Added text merge test
484
        self.tt = TreeTransform(self.wt)
1534.7.181 by Aaron Bentley
Renamed a bunch of functions
485
        self.root = self.tt.trans_id_tree_file_id(self.wt.get_root_id())
1534.7.93 by Aaron Bentley
Added text merge test
486
1534.7.95 by Aaron Bentley
Added more text merge tests
487
def conflict_text(tree, merge):
488
    template = '%s TREE\n%s%s\n%s%s MERGE-SOURCE\n'
489
    return template % ('<' * 7, tree, '=' * 7, merge, '>' * 7)
490
1534.7.93 by Aaron Bentley
Added text merge test
491
492
class TestTransformMerge(TestCaseInTempDir):
493
    def test_text_merge(self):
494
        base = TransformGroup("base")
495
        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
496
        base.tt.new_file('b', base.root, 'b1', 'b')
497
        base.tt.new_file('c', base.root, 'c', 'c')
498
        base.tt.new_file('d', base.root, 'd', 'd')
499
        base.tt.new_file('e', base.root, 'e', 'e')
500
        base.tt.new_file('f', base.root, 'f', 'f')
1534.7.96 by Aaron Bentley
Tested with BASE as directory
501
        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
502
        base.tt.new_directory('h', base.root, 'h')
1534.7.93 by Aaron Bentley
Added text merge test
503
        base.tt.apply()
504
        other = TransformGroup("other")
505
        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
506
        other.tt.new_file('b', other.root, 'b2', 'b')
507
        other.tt.new_file('c', other.root, 'c2', 'c')
508
        other.tt.new_file('d', other.root, 'd', 'd')
509
        other.tt.new_file('e', other.root, 'e2', 'e')
510
        other.tt.new_file('f', other.root, 'f', 'f')
1534.7.96 by Aaron Bentley
Tested with BASE as directory
511
        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
512
        other.tt.new_file('h', other.root, 'h\ni\nj\nk\n', 'h')
1534.7.99 by Aaron Bentley
Handle non-existent BASE properly
513
        other.tt.new_file('i', other.root, 'h\ni\nj\nk\n', 'i')
1534.7.93 by Aaron Bentley
Added text merge test
514
        other.tt.apply()
515
        this = TransformGroup("this")
516
        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
517
        this.tt.new_file('b', this.root, 'b', 'b')
518
        this.tt.new_file('c', this.root, 'c', 'c')
519
        this.tt.new_file('d', this.root, 'd2', 'd')
520
        this.tt.new_file('e', this.root, 'e2', 'e')
521
        this.tt.new_file('f', this.root, 'f', 'f')
1534.7.96 by Aaron Bentley
Tested with BASE as directory
522
        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
523
        this.tt.new_file('h', this.root, '1\n2\n3\n4\n', 'h')
1534.7.99 by Aaron Bentley
Handle non-existent BASE properly
524
        this.tt.new_file('i', this.root, '1\n2\n3\n4\n', 'i')
1534.7.93 by Aaron Bentley
Added text merge test
525
        this.tt.apply()
526
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1534.7.95 by Aaron Bentley
Added more text merge tests
527
        # textual merge
1534.7.93 by Aaron Bentley
Added text merge test
528
        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
529
        # three-way text conflict
530
        self.assertEqual(this.wt.get_file('b').read(), 
531
                         conflict_text('b', 'b2'))
532
        # OTHER wins
533
        self.assertEqual(this.wt.get_file('c').read(), 'c2')
534
        # THIS wins
535
        self.assertEqual(this.wt.get_file('d').read(), 'd2')
536
        # Ambigious clean merge
537
        self.assertEqual(this.wt.get_file('e').read(), 'e2')
538
        # No change
539
        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
540
        # Correct correct results when THIS == OTHER 
1534.7.96 by Aaron Bentley
Tested with BASE as directory
541
        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
542
        # Text conflict when THIS & OTHER are text and BASE is dir
543
        self.assertEqual(this.wt.get_file('h').read(), 
544
                         conflict_text('1\n2\n3\n4\n', 'h\ni\nj\nk\n'))
545
        self.assertEqual(this.wt.get_file_byname('h.THIS').read(),
546
                         '1\n2\n3\n4\n')
547
        self.assertEqual(this.wt.get_file_byname('h.OTHER').read(),
548
                         'h\ni\nj\nk\n')
549
        self.assertEqual(file_kind(this.wt.abspath('h.BASE')), 'directory')
1534.7.99 by Aaron Bentley
Handle non-existent BASE properly
550
        self.assertEqual(this.wt.get_file('i').read(), 
551
                         conflict_text('1\n2\n3\n4\n', 'h\ni\nj\nk\n'))
552
        self.assertEqual(this.wt.get_file_byname('i.THIS').read(),
553
                         '1\n2\n3\n4\n')
554
        self.assertEqual(this.wt.get_file_byname('i.OTHER').read(),
555
                         'h\ni\nj\nk\n')
556
        self.assertEqual(os.path.exists(this.wt.abspath('i.BASE')), False)
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
557
558
    def test_file_merge(self):
1534.7.153 by Aaron Bentley
Handled test cases involving symlinks
559
        if not has_symlinks():
560
            raise TestSkipped('Symlinks are not supported on this platform')
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
561
        base = TransformGroup("BASE")
562
        this = TransformGroup("THIS")
563
        other = TransformGroup("OTHER")
564
        for tg in this, base, other:
565
            tg.tt.new_directory('a', tg.root, 'a')
566
            tg.tt.new_symlink('b', tg.root, 'b', 'b')
567
            tg.tt.new_file('c', tg.root, 'c', 'c')
568
            tg.tt.new_symlink('d', tg.root, tg.name, 'd')
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
569
        targets = ((base, 'base-e', 'base-f', None, None), 
570
                   (this, 'other-e', 'this-f', 'other-g', 'this-h'), 
571
                   (other, 'other-e', None, 'other-g', 'other-h'))
572
        for tg, e_target, f_target, g_target, h_target in targets:
573
            for link, target in (('e', e_target), ('f', f_target), 
574
                                 ('g', g_target), ('h', h_target)):
575
                if target is not None:
576
                    tg.tt.new_symlink(link, tg.root, target, link)
1534.7.102 by Aaron Bentley
Deleted old pre-conflict contents
577
578
        for tg in this, base, other:
1534.7.101 by Aaron Bentley
Got conflicts on symlinks working properly
579
            tg.tt.apply()
580
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
581
        self.assertIs(os.path.isdir(this.wt.abspath('a')), True)
582
        self.assertIs(os.path.islink(this.wt.abspath('b')), True)
583
        self.assertIs(os.path.isfile(this.wt.abspath('c')), True)
584
        for suffix in ('THIS', 'BASE', 'OTHER'):
585
            self.assertEqual(os.readlink(this.wt.abspath('d.'+suffix)), suffix)
1534.7.102 by Aaron Bentley
Deleted old pre-conflict contents
586
        self.assertIs(os.path.lexists(this.wt.abspath('d')), False)
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
587
        self.assertEqual(this.wt.id2path('d'), 'd.OTHER')
588
        self.assertEqual(this.wt.id2path('f'), 'f.THIS')
1534.7.102 by Aaron Bentley
Deleted old pre-conflict contents
589
        self.assertEqual(os.readlink(this.wt.abspath('e')), 'other-e')
590
        self.assertIs(os.path.lexists(this.wt.abspath('e.THIS')), False)
591
        self.assertIs(os.path.lexists(this.wt.abspath('e.OTHER')), False)
592
        self.assertIs(os.path.lexists(this.wt.abspath('e.BASE')), False)
1534.7.104 by Aaron Bentley
Fixed set_versioned, enhanced conflict testing
593
        self.assertIs(os.path.lexists(this.wt.abspath('g')), True)
594
        self.assertIs(os.path.lexists(this.wt.abspath('g.BASE')), False)
595
        self.assertIs(os.path.lexists(this.wt.abspath('h')), False)
596
        self.assertIs(os.path.lexists(this.wt.abspath('h.BASE')), False)
597
        self.assertIs(os.path.lexists(this.wt.abspath('h.THIS')), True)
598
        self.assertIs(os.path.lexists(this.wt.abspath('h.OTHER')), True)
1534.7.105 by Aaron Bentley
Got merge with rename working
599
600
    def test_filename_merge(self):
601
        base = TransformGroup("BASE")
602
        this = TransformGroup("THIS")
603
        other = TransformGroup("OTHER")
604
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, 'a') 
605
                                   for t in [base, this, other]]
606
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, 'b') 
607
                                   for t in [base, this, other]]
608
        base.tt.new_directory('c', base_a, 'c')
609
        this.tt.new_directory('c1', this_a, 'c')
610
        other.tt.new_directory('c', other_b, 'c')
611
612
        base.tt.new_directory('d', base_a, 'd')
613
        this.tt.new_directory('d1', this_b, 'd')
614
        other.tt.new_directory('d', other_a, 'd')
615
616
        base.tt.new_directory('e', base_a, 'e')
617
        this.tt.new_directory('e', this_a, 'e')
618
        other.tt.new_directory('e1', other_b, 'e')
619
620
        base.tt.new_directory('f', base_a, 'f')
621
        this.tt.new_directory('f1', this_b, 'f')
622
        other.tt.new_directory('f1', other_b, 'f')
623
624
        for tg in [this, base, other]:
625
            tg.tt.apply()
626
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1534.7.176 by abentley
Fixed up tests for Windows
627
        self.assertEqual(this.wt.id2path('c'), pathjoin('b/c1'))
628
        self.assertEqual(this.wt.id2path('d'), pathjoin('b/d1'))
629
        self.assertEqual(this.wt.id2path('e'), pathjoin('b/e1'))
630
        self.assertEqual(this.wt.id2path('f'), pathjoin('b/f1'))
1534.7.105 by Aaron Bentley
Got merge with rename working
631
632
    def test_filename_merge_conflicts(self):
633
        base = TransformGroup("BASE")
634
        this = TransformGroup("THIS")
635
        other = TransformGroup("OTHER")
636
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, 'a') 
637
                                   for t in [base, this, other]]
638
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, 'b') 
639
                                   for t in [base, this, other]]
640
641
        base.tt.new_file('g', base_a, 'g', 'g')
642
        other.tt.new_file('g1', other_b, 'g1', 'g')
643
644
        base.tt.new_file('h', base_a, 'h', 'h')
645
        this.tt.new_file('h1', this_b, 'h1', 'h')
646
647
        base.tt.new_file('i', base.root, 'i', 'i')
1534.7.153 by Aaron Bentley
Handled test cases involving symlinks
648
        other.tt.new_directory('i1', this_b, 'i')
1534.7.105 by Aaron Bentley
Got merge with rename working
649
650
        for tg in [this, base, other]:
651
            tg.tt.apply()
652
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
653
1534.7.176 by abentley
Fixed up tests for Windows
654
        self.assertEqual(this.wt.id2path('g'), pathjoin('b/g1.OTHER'))
1534.7.105 by Aaron Bentley
Got merge with rename working
655
        self.assertIs(os.path.lexists(this.wt.abspath('b/g1.BASE')), True)
656
        self.assertIs(os.path.lexists(this.wt.abspath('b/g1.THIS')), False)
1534.7.176 by abentley
Fixed up tests for Windows
657
        self.assertEqual(this.wt.id2path('h'), pathjoin('b/h1.THIS'))
1534.7.105 by Aaron Bentley
Got merge with rename working
658
        self.assertIs(os.path.lexists(this.wt.abspath('b/h1.BASE')), True)
659
        self.assertIs(os.path.lexists(this.wt.abspath('b/h1.OTHER')), False)
1534.7.176 by abentley
Fixed up tests for Windows
660
        self.assertEqual(this.wt.id2path('i'), pathjoin('b/i1.OTHER'))