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