14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
from cStringIO import StringIO
22
from bzrlib.branch import Branch
23
import bzrlib.bzrdir as bzrdir
24
from bzrlib.bzrdir import BzrDir
25
from bzrlib.conflicts import *
26
import bzrlib.errors as errors
27
from bzrlib.errors import NotBranchError, NotVersionedError
28
27
from bzrlib.lockdir import LockDir
29
from bzrlib.osutils import pathjoin, getcwd, has_symlinks
30
from bzrlib.tests import TestCaseWithTransport, TestSkipped
31
from bzrlib.trace import mutter
32
from bzrlib.transport import get_transport
33
import bzrlib.workingtree as workingtree
34
from bzrlib.workingtree import (TreeEntry, TreeDirectory, TreeFile, TreeLink,
28
from bzrlib.mutabletree import needs_tree_write_lock
29
from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
30
from bzrlib.workingtree import (
37
38
class TestTreeDirectory(TestCaseWithTransport):
77
78
workingtree.WorkingTreeFormat.set_default_format(old_format)
78
79
self.assertEqual(old_format, workingtree.WorkingTreeFormat.get_default_format())
82
tree = self.make_branch_and_tree('.')
83
open_direct = workingtree.WorkingTree.open('.')
84
self.assertEqual(tree.basedir, open_direct.basedir)
85
open_no_args = workingtree.WorkingTree.open()
86
self.assertEqual(tree.basedir, open_no_args.basedir)
88
def test_open_containing(self):
89
tree = self.make_branch_and_tree('.')
90
open_direct, relpath = workingtree.WorkingTree.open_containing('.')
91
self.assertEqual(tree.basedir, open_direct.basedir)
92
self.assertEqual('', relpath)
93
open_no_args, relpath = workingtree.WorkingTree.open_containing()
94
self.assertEqual(tree.basedir, open_no_args.basedir)
95
self.assertEqual('', relpath)
96
open_subdir, relpath = workingtree.WorkingTree.open_containing('subdir')
97
self.assertEqual(tree.basedir, open_subdir.basedir)
98
self.assertEqual('subdir', relpath)
81
101
class SampleTreeFormat(workingtree.WorkingTreeFormat):
82
102
"""A sample format
84
this format is initializable, unsupported to aid in testing the
104
this format is initializable, unsupported to aid in testing the
85
105
open and open_downlevel routines.
206
257
self.assertEquals(our_lock.peek(), None)
259
def test_missing_pending_merges(self):
260
control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
261
control.create_repository()
262
control.create_branch()
263
tree = workingtree.WorkingTreeFormat3().initialize(control)
264
tree._transport.delete("pending-merges")
265
self.assertEqual([], tree.get_parent_ids())
268
class TestFormat2WorkingTree(TestCaseWithTransport):
269
"""Tests that are specific to format 2 trees."""
208
271
def create_format2_tree(self, url):
209
return BzrDir.create_standalone_workingtree(url)
272
return self.make_branch_and_tree(
273
url, format=bzrdir.BzrDirFormat6())
211
def test_conflicts_format2(self):
275
def test_conflicts(self):
212
276
# test backwards compatability
213
277
tree = self.create_format2_tree('.')
214
278
self.assertRaises(errors.UnsupportedOperation, tree.set_conflicts,
216
280
file('lala.BASE', 'wb').write('labase')
217
expected = ContentsConflict('lala')
281
expected = conflicts.ContentsConflict('lala')
218
282
self.assertEqual(list(tree.conflicts()), [expected])
219
283
file('lala', 'wb').write('la')
220
284
tree.add('lala', 'lala-id')
221
expected = ContentsConflict('lala', file_id='lala-id')
285
expected = conflicts.ContentsConflict('lala', file_id='lala-id')
222
286
self.assertEqual(list(tree.conflicts()), [expected])
223
287
file('lala.THIS', 'wb').write('lathis')
224
288
file('lala.OTHER', 'wb').write('laother')
225
289
# When "text conflict"s happen, stem, THIS and OTHER are text
226
expected = TextConflict('lala', file_id='lala-id')
290
expected = conflicts.TextConflict('lala', file_id='lala-id')
227
291
self.assertEqual(list(tree.conflicts()), [expected])
228
292
os.unlink('lala.OTHER')
229
293
os.mkdir('lala.OTHER')
230
expected = ContentsConflict('lala', file_id='lala-id')
294
expected = conflicts.ContentsConflict('lala', file_id='lala-id')
231
295
self.assertEqual(list(tree.conflicts()), [expected])
298
class InstrumentedTree(object):
299
"""A instrumented tree to check the needs_tree_write_lock decorator."""
304
def lock_tree_write(self):
305
self._locks.append('t')
307
@needs_tree_write_lock
308
def method_with_tree_write_lock(self, *args, **kwargs):
309
"""A lock_tree_write decorated method that returns its arguments."""
312
@needs_tree_write_lock
313
def method_that_raises(self):
314
"""This method causes an exception when called with parameters.
316
This allows the decorator code to be checked - it should still call
321
self._locks.append('u')
324
class TestInstrumentedTree(TestCase):
326
def test_needs_tree_write_lock(self):
327
"""@needs_tree_write_lock should be semantically transparent."""
328
tree = InstrumentedTree()
330
'method_with_tree_write_lock',
331
tree.method_with_tree_write_lock.__name__)
332
self.assertDocstring(
333
"A lock_tree_write decorated method that returns its arguments.",
334
tree.method_with_tree_write_lock)
337
result = tree.method_with_tree_write_lock(1,2,3, a='b')
338
self.assertEqual((args, kwargs), result)
339
self.assertEqual(['t', 'u'], tree._locks)
340
self.assertRaises(TypeError, tree.method_that_raises, 'foo')
341
self.assertEqual(['t', 'u', 't', 'u'], tree._locks)
344
class TestRevert(TestCaseWithTransport):
346
def test_revert_conflicts_recursive(self):
347
this_tree = self.make_branch_and_tree('this-tree')
348
self.build_tree_contents([('this-tree/foo/',),
349
('this-tree/foo/bar', 'bar')])
350
this_tree.add(['foo', 'foo/bar'])
351
this_tree.commit('created foo/bar')
352
other_tree = this_tree.bzrdir.sprout('other-tree').open_workingtree()
353
self.build_tree_contents([('other-tree/foo/bar', 'baz')])
354
other_tree.commit('changed bar')
355
self.build_tree_contents([('this-tree/foo/bar', 'qux')])
356
this_tree.commit('changed qux')
357
this_tree.merge_from_branch(other_tree.branch)
358
self.assertEqual(1, len(this_tree.conflicts()))
359
this_tree.revert(['foo'])
360
self.assertEqual(0, len(this_tree.conflicts()))
363
class TestAutoResolve(TestCaseWithTransport):
365
def test_auto_resolve(self):
366
base = self.make_branch_and_tree('base')
367
self.build_tree_contents([('base/hello', 'Hello')])
368
base.add('hello', 'hello_id')
370
other = base.bzrdir.sprout('other').open_workingtree()
371
self.build_tree_contents([('other/hello', 'hELLO')])
372
other.commit('Case switch')
373
this = base.bzrdir.sprout('this').open_workingtree()
374
self.failUnlessExists('this/hello')
375
self.build_tree_contents([('this/hello', 'Hello World')])
376
this.commit('Add World')
377
this.merge_from_branch(other.branch)
378
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
381
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
383
self.build_tree_contents([('this/hello', '<<<<<<<')])
385
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
387
self.build_tree_contents([('this/hello', '=======')])
389
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
391
self.build_tree_contents([('this/hello', '\n>>>>>>>')])
392
remaining, resolved = this.auto_resolve()
393
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
395
self.assertEqual([], resolved)
396
self.build_tree_contents([('this/hello', 'hELLO wORLD')])
397
remaining, resolved = this.auto_resolve()
398
self.assertEqual([], this.conflicts())
399
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
401
self.failIfExists('this/hello.BASE')
403
def test_auto_resolve_dir(self):
404
tree = self.make_branch_and_tree('tree')
405
self.build_tree(['tree/hello/'])
406
tree.add('hello', 'hello-id')
407
file_conflict = conflicts.TextConflict('file', 'hello-id')
408
tree.set_conflicts(conflicts.ConflictList([file_conflict]))
412
class TestFindTrees(TestCaseWithTransport):
414
def test_find_trees(self):
415
self.make_branch_and_tree('foo')
416
self.make_branch_and_tree('foo/bar')
417
# Sticking a tree inside a control dir is heinous, so let's skip it
418
self.make_branch_and_tree('foo/.bzr/baz')
419
self.make_branch('qux')
420
trees = workingtree.WorkingTree.find_trees('.')
421
self.assertEqual(2, len(list(trees)))