/brz/remove-bazaar

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