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