235
222
control.create_repository()
236
223
control.create_branch()
237
224
tree = workingtree.WorkingTreeFormat3().initialize(control)
238
tree._transport.delete("pending-merges")
225
tree._control_files._transport.delete("pending-merges")
239
226
self.assertEqual([], tree.get_parent_ids())
229
class TestWorkingTreeFormat4(TestCaseWithTransport):
230
"""Tests specific to WorkingTreeFormat4."""
232
def test_disk_layout(self):
233
control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
234
control.create_repository()
235
control.create_branch()
236
tree = workingtree.WorkingTreeFormat4().initialize(control)
238
# format 'Bazaar Working Tree format 4'
240
t = control.get_workingtree_transport(None)
241
self.assertEqualDiff('Bazaar Working Tree format 4\n',
242
t.get('format').read())
243
self.assertEqualDiff('### bzr hashcache v5\n',
244
t.get('stat-cache').read())
245
self.assertFalse(t.has('inventory.basis'))
246
# no last-revision file means 'None' or 'NULLREVISION'
247
self.assertFalse(t.has('last-revision'))
248
# TODO RBC 20060210 do a commit, check the inventory.basis is created
249
# correctly and last-revision file becomes present.
250
# manually make a dirstate toc check the format is as desired.
251
state = dirstate.DirState.on_file(t.local_abspath('dirstate'))
252
self.assertEqual([], state.get_parent_ids())
254
def test_uses_lockdir(self):
255
"""WorkingTreeFormat4 uses its own LockDir:
257
- lock is a directory
258
- when the WorkingTree is locked, LockDir can see that
260
# this test could be factored into a subclass of tests common to both
261
# format 3 and 4, but for now its not much of an issue as there is only one in common.
262
t = self.get_transport()
263
tree = self.make_workingtree()
264
self.assertIsDirectory('.bzr', t)
265
self.assertIsDirectory('.bzr/checkout', t)
266
self.assertIsDirectory('.bzr/checkout/lock', t)
267
our_lock = LockDir(t, '.bzr/checkout/lock')
268
self.assertEquals(our_lock.peek(), None)
270
self.assertTrue(our_lock.peek())
272
self.assertEquals(our_lock.peek(), None)
274
def make_workingtree(self):
276
dir = bzrdir.BzrDirMetaFormat1().initialize(url)
277
repo = dir.create_repository()
278
branch = dir.create_branch()
280
return workingtree.WorkingTreeFormat4().initialize(dir)
281
except errors.NotLocalUrl:
282
raise TestSkipped('Not a local URL')
284
# TODO: test that dirstate also stores & retrieves the parent list of
285
# workingtree-parent revisions, including when they have multiple parents.
286
# (in other words, the case when we're constructing a merge of
287
# revisions which are themselves merges.)
289
# The simplest case is that the the workingtree's primary
290
# parent tree can be retrieved. This is required for all WorkingTrees,
291
# and covered by the generic tests.
293
def test_dirstate_stores_all_parent_inventories(self):
294
tree = self.make_workingtree()
296
# We're going to build in tree a working tree
297
# with three parent trees, with some files in common.
299
# We really don't want to do commit or merge in the new dirstate-based
300
# tree, because that might not work yet. So instead we build
301
# revisions elsewhere and pull them across, doing by hand part of the
302
# work that merge would do.
304
subtree = self.make_branch_and_tree('subdir')
305
# writelock the tree so its repository doesn't get readlocked by
306
# the revision tree locks. This works around the bug where we dont
307
# permit lock upgrading.
309
self.addCleanup(subtree.unlock)
310
self.build_tree(['subdir/file-a',])
311
subtree.add(['file-a'], ['id-a'])
312
rev1 = subtree.commit('commit in subdir')
313
rev1_tree = subtree.basis_tree()
314
rev1_tree.lock_read()
315
self.addCleanup(rev1_tree.unlock)
317
subtree2 = subtree.bzrdir.sprout('subdir2').open_workingtree()
318
self.build_tree(['subdir2/file-b'])
319
subtree2.add(['file-b'], ['id-b'])
320
rev2 = subtree2.commit('commit in subdir2')
321
rev2_tree = subtree2.basis_tree()
322
rev2_tree.lock_read()
323
self.addCleanup(rev2_tree.unlock)
325
subtree.merge_from_branch(subtree2.branch)
326
rev3 = subtree.commit('merge from subdir2')
327
rev3_tree = subtree.basis_tree()
328
rev3_tree.lock_read()
329
self.addCleanup(rev3_tree.unlock)
331
repo = tree.branch.repository
332
repo.fetch(subtree.branch.repository, rev3)
333
# will also pull the others...
335
# tree doesn't contain a text merge yet but we'll just
336
# set the parents as if a merge had taken place.
337
# this should cause the tree data to be folded into the
339
tree.set_parent_trees([
342
(rev3, rev3_tree), ])
344
# now we should be able to get them back out
345
self.assertTreesEqual(tree.revision_tree(rev1), rev1_tree)
346
self.assertTreesEqual(tree.revision_tree(rev2), rev2_tree)
347
self.assertTreesEqual(tree.revision_tree(rev3), rev3_tree)
349
def test_dirstate_doesnt_read_parents_from_repo_when_setting(self):
350
"""Setting parent trees on a dirstate working tree takes
351
the trees it's given and doesn't need to read them from the
354
tree = self.make_workingtree()
356
subtree = self.make_branch_and_tree('subdir')
357
rev1 = subtree.commit('commit in subdir')
358
rev1_tree = subtree.basis_tree()
359
rev1_tree.lock_read()
360
self.addCleanup(rev1_tree.unlock)
362
tree.branch.pull(subtree.branch)
364
# break the repository's legs to make sure it only uses the trees
365
# it's given; any calls to forbidden methods will raise an
367
repo = tree.branch.repository
368
repo.get_revision = self.fail
369
repo.get_inventory = self.fail
370
repo.get_inventory_xml = self.fail
371
# try to set the parent trees.
372
tree.set_parent_trees([(rev1, rev1_tree)])
374
def test_dirstate_doesnt_read_from_repo_when_returning_cache_tree(self):
375
"""Getting parent trees from a dirstate tree does not read from the
376
repos inventory store. This is an important part of the dirstate
377
performance optimisation work.
379
tree = self.make_workingtree()
381
subtree = self.make_branch_and_tree('subdir')
382
# writelock the tree so its repository doesn't get readlocked by
383
# the revision tree locks. This works around the bug where we dont
384
# permit lock upgrading.
386
self.addCleanup(subtree.unlock)
387
rev1 = subtree.commit('commit in subdir')
388
rev1_tree = subtree.basis_tree()
389
rev1_tree.lock_read()
390
self.addCleanup(rev1_tree.unlock)
391
rev2 = subtree.commit('second commit in subdir', allow_pointless=True)
392
rev2_tree = subtree.basis_tree()
393
rev2_tree.lock_read()
394
self.addCleanup(rev2_tree.unlock)
396
tree.branch.pull(subtree.branch)
398
# break the repository's legs to make sure it only uses the trees
399
# it's given; any calls to forbidden methods will raise an
401
repo = tree.branch.repository
402
# dont uncomment this: the revision object must be accessed to
403
# answer 'get_parent_ids' for the revision tree- dirstate does not
404
# cache the parents of a parent tree at this point.
405
#repo.get_revision = self.fail
406
repo.get_inventory = self.fail
407
repo.get_inventory_xml = self.fail
408
# set the parent trees.
409
tree.set_parent_trees([(rev1, rev1_tree), (rev2, rev2_tree)])
410
# read the first tree
411
result_rev1_tree = tree.revision_tree(rev1)
413
result_rev2_tree = tree.revision_tree(rev2)
414
# compare - there should be no differences between the handed and
416
self.assertTreesEqual(rev1_tree, result_rev1_tree)
417
self.assertTreesEqual(rev2_tree, result_rev2_tree)
419
def test_dirstate_doesnt_cache_non_parent_trees(self):
420
"""Getting parent trees from a dirstate tree does not read from the
421
repos inventory store. This is an important part of the dirstate
422
performance optimisation work.
424
tree = self.make_workingtree()
426
# make a tree that we can try for, which is able to be returned but
428
subtree = self.make_branch_and_tree('subdir')
429
rev1 = subtree.commit('commit in subdir')
430
tree.branch.pull(subtree.branch)
432
self.assertRaises(errors.NoSuchRevision, tree.revision_tree, rev1)
434
def test_no_dirstate_outside_lock(self):
435
# temporary test until the code is mature enough to test from outside.
436
"""Getting a dirstate object fails if there is no lock."""
437
def lock_and_call_current_dirstate(tree, lock_method):
438
getattr(tree, lock_method)()
439
tree.current_dirstate()
441
tree = self.make_workingtree()
442
self.assertRaises(errors.ObjectNotLocked, tree.current_dirstate)
443
lock_and_call_current_dirstate(tree, 'lock_read')
444
self.assertRaises(errors.ObjectNotLocked, tree.current_dirstate)
445
lock_and_call_current_dirstate(tree, 'lock_write')
446
self.assertRaises(errors.ObjectNotLocked, tree.current_dirstate)
447
lock_and_call_current_dirstate(tree, 'lock_tree_write')
448
self.assertRaises(errors.ObjectNotLocked, tree.current_dirstate)
450
def test_new_dirstate_on_new_lock(self):
451
# until we have detection for when a dirstate can be reused, we
452
# want to reparse dirstate on every new lock.
453
known_dirstates = set()
454
def lock_and_compare_all_current_dirstate(tree, lock_method):
455
getattr(tree, lock_method)()
456
state = tree.current_dirstate()
457
self.assertFalse(state in known_dirstates)
458
known_dirstates.add(state)
460
tree = self.make_workingtree()
461
# lock twice with each type to prevent silly per-lock-type bugs.
462
# each lock and compare looks for a unique state object.
463
lock_and_compare_all_current_dirstate(tree, 'lock_read')
464
lock_and_compare_all_current_dirstate(tree, 'lock_read')
465
lock_and_compare_all_current_dirstate(tree, 'lock_tree_write')
466
lock_and_compare_all_current_dirstate(tree, 'lock_tree_write')
467
lock_and_compare_all_current_dirstate(tree, 'lock_write')
468
lock_and_compare_all_current_dirstate(tree, 'lock_write')
242
471
class TestFormat2WorkingTree(TestCaseWithTransport):
243
472
"""Tests that are specific to format 2 trees."""
245
474
def create_format2_tree(self, url):
246
475
return self.make_branch_and_tree(
247
url, format=bzrdir.BzrDirFormat6())
476
url, format=bzrlib.bzrdir.BzrDirFormat6())
249
478
def test_conflicts(self):
250
479
# test backwards compatability
313
555
self.assertEqual(['t', 'u'], tree._locks)
314
556
self.assertRaises(TypeError, tree.method_that_raises, 'foo')
315
557
self.assertEqual(['t', 'u', 't', 'u'], tree._locks)
318
class TestRevert(TestCaseWithTransport):
320
def test_revert_conflicts_recursive(self):
321
this_tree = self.make_branch_and_tree('this-tree')
322
self.build_tree_contents([('this-tree/foo/',),
323
('this-tree/foo/bar', 'bar')])
324
this_tree.add(['foo', 'foo/bar'])
325
this_tree.commit('created foo/bar')
326
other_tree = this_tree.bzrdir.sprout('other-tree').open_workingtree()
327
self.build_tree_contents([('other-tree/foo/bar', 'baz')])
328
other_tree.commit('changed bar')
329
self.build_tree_contents([('this-tree/foo/bar', 'qux')])
330
this_tree.commit('changed qux')
331
this_tree.merge_from_branch(other_tree.branch)
332
self.assertEqual(1, len(this_tree.conflicts()))
333
this_tree.revert(['foo'])
334
self.assertEqual(0, len(this_tree.conflicts()))
337
class TestAutoResolve(TestCaseWithTransport):
339
def test_auto_resolve(self):
340
base = self.make_branch_and_tree('base')
341
self.build_tree_contents([('base/hello', 'Hello')])
342
base.add('hello', 'hello_id')
344
other = base.bzrdir.sprout('other').open_workingtree()
345
self.build_tree_contents([('other/hello', 'hELLO')])
346
other.commit('Case switch')
347
this = base.bzrdir.sprout('this').open_workingtree()
348
self.failUnlessExists('this/hello')
349
self.build_tree_contents([('this/hello', 'Hello World')])
350
this.commit('Add World')
351
this.merge_from_branch(other.branch)
352
self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
355
self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
357
self.build_tree_contents([('this/hello', '<<<<<<<')])
359
self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
361
self.build_tree_contents([('this/hello', '=======')])
363
self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
365
self.build_tree_contents([('this/hello', '\n>>>>>>>')])
366
remaining, resolved = this.auto_resolve()
367
self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
369
self.assertEqual([], resolved)
370
self.build_tree_contents([('this/hello', 'hELLO wORLD')])
371
remaining, resolved = this.auto_resolve()
372
self.assertEqual([], this.conflicts())
373
self.assertEqual([conflicts.TextConflict('hello', None, 'hello_id')],
375
self.failIfExists('this/hello.BASE')
377
def test_auto_resolve_dir(self):
378
tree = self.make_branch_and_tree('tree')
379
self.build_tree(['tree/hello/'])
380
tree.add('hello', 'hello-id')
381
file_conflict = conflicts.TextConflict('file', None, 'hello-id')
382
tree.set_conflicts(conflicts.ConflictList([file_conflict]))
386
class TestFindTrees(TestCaseWithTransport):
388
def test_find_trees(self):
389
self.make_branch_and_tree('foo')
390
self.make_branch_and_tree('foo/bar')
391
# Sticking a tree inside a control dir is heinous, so let's skip it
392
self.make_branch_and_tree('foo/.bzr/baz')
393
self.make_branch('qux')
394
trees = workingtree.WorkingTree.find_trees('.')
395
self.assertEqual(2, len(list(trees)))