237
247
first_revision = tree.commit('first post')
238
248
tree.add_parent_tree(('second', None))
239
249
self.assertConsistentParents([first_revision, 'second'], tree)
252
class UpdateToOneParentViaDeltaTests(TestParents):
253
"""Tests for the update_to_one_parent_via_delta call.
255
This is intuitively defined as 'apply an inventory delta to the basis and
256
discard other parents', but for trees that have an inventory that is not
257
managed as a tree-by-id, the implementation requires roughly duplicated
258
tests with those for apply_inventory_delta on the main tree.
261
def assertDeltaApplicationResultsInExpectedBasis(self, tree, revid, delta,
263
tree.update_to_one_parent_via_delta(revid, delta)
264
# check the last revision was adjusted to rev_id
265
self.assertEqual(revid, tree.last_revision())
266
# check the parents are what we expect
267
self.assertEqual([revid], tree.get_parent_ids())
268
# check that the basis tree has the inventory we expect from applying
270
result_basis = tree.basis_tree()
271
result_basis.lock_read()
272
self.addCleanup(result_basis.unlock)
273
self.assertEqual(expected_inventory, result_basis.inventory)
275
def make_inv_delta(self, old, new):
276
"""Make an inventory delta from two inventories."""
277
old_ids = set(old._byid.iterkeys())
278
new_ids = set(new._byid.iterkeys())
279
adds = new_ids - old_ids
280
deletes = old_ids - new_ids
281
common = old_ids.intersection(new_ids)
283
for file_id in deletes:
284
delta.append((old.id2path(file_id), None, file_id, None))
286
delta.append((None, new.id2path(file_id), file_id, new[file_id]))
287
for file_id in common:
288
if old[file_id] != new[file_id]:
289
delta.append((old.id2path(file_id), new.id2path(file_id),
290
file_id, new[file_id]))
293
def fake_up_revision(self, tree, revid, shape):
296
tree.branch.repository.start_write_group()
298
if shape.root.revision is None:
299
shape.root.revision = revid
300
sha1 = tree.branch.repository.add_inventory(revid, shape, [])
301
rev = Revision(timestamp=0,
303
committer="Foo Bar <foo@example.com>",
307
tree.branch.repository.add_revision(revid, rev)
309
tree.branch.repository.abort_write_group()
312
tree.branch.repository.commit_write_group()
316
def add_entry(self, inv, rev_id, entry):
317
entry.revision = rev_id
320
def add_dir(self, inv, rev_id, file_id, parent_id, name):
321
new_dir = InventoryDirectory(file_id, name, parent_id)
322
self.add_entry(inv, rev_id, new_dir)
324
def add_file(self, inv, rev_id, file_id, parent_id, name, sha, size):
325
new_file = InventoryFile(file_id, name, parent_id)
326
new_file.text_sha1 = sha
327
new_file.text_size = size
328
self.add_entry(inv, rev_id, new_file)
330
def add_link(self, inv, rev_id, file_id, parent_id, name, target):
331
new_link = InventoryLink(file_id, name, parent_id)
332
new_link.symlink_target = target
333
self.add_entry(inv, rev_id, new_link)
335
def add_new_root(self, new_shape, old_revid, new_revid):
336
if self.bzrdir_format.repository_format.rich_root_data:
337
self.add_dir(new_shape, old_revid, 'root-id', None, '')
339
self.add_dir(new_shape, new_revid, 'root-id', None, '')
341
def assertTransitionFromBasisToShape(self, basis_shape, basis_revid,
342
new_shape, new_revid, extra_parent=None):
343
# set the inventory revision ids.
344
basis_shape.revision_id = basis_revid
345
new_shape.revision_id = new_revid
346
delta = self.make_inv_delta(basis_shape, new_shape)
347
tree = self.make_branch_and_tree('tree')
348
# the shapes need to be in the tree's repository to be able to set them
349
# as a parent, but the file content is not needed.
350
if basis_revid is not None:
351
self.fake_up_revision(tree, basis_revid, basis_shape)
352
parents = [basis_revid]
353
if extra_parent is not None:
354
parents.append(extra_parent)
355
tree.set_parent_ids(parents)
356
self.fake_up_revision(tree, new_revid, new_shape)
357
self.assertDeltaApplicationResultsInExpectedBasis(tree, new_revid,
359
osutils.rmtree('tree')
361
def test_no_parents_just_root(self):
362
"""Test doing an empty commit - no parent, set a root only."""
363
basis_shape = Inventory(root_id=None) # empty tree
364
new_shape = Inventory() # tree with a root
365
self.assertTransitionFromBasisToShape(basis_shape, None, new_shape,
368
def test_no_parents_full_tree(self):
369
"""Test doing a regular initial commit with files and dirs."""
370
basis_shape = Inventory(root_id=None) # empty tree
372
new_shape = Inventory(root_id=None)
373
self.add_dir(new_shape, revid, 'root-id', None, '')
374
self.add_link(new_shape, revid, 'link-id', 'root-id', 'link', 'target')
375
self.add_file(new_shape, revid, 'file-id', 'root-id', 'file', '1' * 32,
377
self.add_dir(new_shape, revid, 'dir-id', 'root-id', 'dir')
378
self.add_file(new_shape, revid, 'subfile-id', 'dir-id', 'subfile',
380
self.assertTransitionFromBasisToShape(basis_shape, None, new_shape,
383
def test_file_content_change(self):
384
old_revid = 'old-parent'
385
basis_shape = Inventory(root_id=None)
386
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
387
self.add_file(basis_shape, old_revid, 'file-id', 'root-id', 'file',
389
new_revid = 'new-parent'
390
new_shape = Inventory(root_id=None)
391
self.add_new_root(new_shape, old_revid, new_revid)
392
self.add_file(new_shape, new_revid, 'file-id', 'root-id', 'file',
394
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
395
new_shape, new_revid)
397
def test_link_content_change(self):
398
old_revid = 'old-parent'
399
basis_shape = Inventory(root_id=None)
400
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
401
self.add_link(basis_shape, old_revid, 'link-id', 'root-id', 'link',
403
new_revid = 'new-parent'
404
new_shape = Inventory(root_id=None)
405
self.add_new_root(new_shape, old_revid, new_revid)
406
self.add_link(new_shape, new_revid, 'link-id', 'root-id', 'link',
408
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
409
new_shape, new_revid)
411
def test_kind_changes(self):
412
def do_file(inv, revid):
413
self.add_file(inv, revid, 'path-id', 'root-id', 'path', '1' * 32,
415
def do_link(inv, revid):
416
self.add_link(inv, revid, 'path-id', 'root-id', 'path', 'target')
417
def do_dir(inv, revid):
418
self.add_dir(inv, revid, 'path-id', 'root-id', 'path')
419
for old_factory in (do_file, do_link, do_dir):
420
for new_factory in (do_file, do_link, do_dir):
421
if old_factory == new_factory:
423
old_revid = 'old-parent'
424
basis_shape = Inventory(root_id=None)
425
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
426
old_factory(basis_shape, old_revid)
427
new_revid = 'new-parent'
428
new_shape = Inventory(root_id=None)
429
self.add_new_root(new_shape, old_revid, new_revid)
430
new_factory(new_shape, new_revid)
431
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
432
new_shape, new_revid)
434
def test_content_from_second_parent_is_dropped(self):
435
left_revid = 'left-parent'
436
basis_shape = Inventory(root_id=None)
437
self.add_dir(basis_shape, left_revid, 'root-id', None, '')
438
self.add_link(basis_shape, left_revid, 'link-id', 'root-id', 'link',
440
# the right shape has content - file, link, subdir with a child,
441
# that should all be discarded by the call.
442
right_revid = 'right-parent'
443
right_shape = Inventory(root_id=None)
444
self.add_dir(right_shape, left_revid, 'root-id', None, '')
445
self.add_link(right_shape, right_revid, 'link-id', 'root-id', 'link',
447
self.add_dir(right_shape, right_revid, 'subdir-id', 'root-id', 'dir')
448
self.add_file(right_shape, right_revid, 'file-id', 'subdir-id', 'file',
450
new_revid = 'new-parent'
451
new_shape = Inventory(root_id=None)
452
self.add_new_root(new_shape, left_revid, new_revid)
453
self.add_link(new_shape, new_revid, 'link-id', 'root-id', 'link',
455
self.assertTransitionFromBasisToShape(basis_shape, left_revid,
456
new_shape, new_revid, right_revid)
458
def test_parent_id_changed(self):
459
# test that when the only change to an entry is its parent id changing
460
# that it is handled correctly (that is it keeps the same path)
461
old_revid = 'old-parent'
462
basis_shape = Inventory(root_id=None)
463
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
464
self.add_dir(basis_shape, old_revid, 'orig-parent-id', 'root-id', 'dir')
465
self.add_dir(basis_shape, old_revid, 'dir-id', 'orig-parent-id', 'dir')
466
new_revid = 'new-parent'
467
new_shape = Inventory(root_id=None)
468
self.add_new_root(new_shape, old_revid, new_revid)
469
self.add_dir(new_shape, new_revid, 'new-parent-id', 'root-id', 'dir')
470
self.add_dir(new_shape, new_revid, 'dir-id', 'new-parent-id', 'dir')
471
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
472
new_shape, new_revid)
474
def test_name_changed(self):
475
# test that when the only change to an entry is its name changing that
476
# it is handled correctly (that is it keeps the same parent id)
477
old_revid = 'old-parent'
478
basis_shape = Inventory(root_id=None)
479
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
480
self.add_dir(basis_shape, old_revid, 'parent-id', 'root-id', 'origdir')
481
self.add_dir(basis_shape, old_revid, 'dir-id', 'parent-id', 'olddir')
482
new_revid = 'new-parent'
483
new_shape = Inventory(root_id=None)
484
self.add_new_root(new_shape, old_revid, new_revid)
485
self.add_dir(new_shape, new_revid, 'parent-id', 'root-id', 'newdir')
486
self.add_dir(new_shape, new_revid, 'dir-id', 'parent-id', 'newdir')
487
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
488
new_shape, new_revid)
490
def test_path_swap(self):
491
# test a A->B and B->A path swap.
492
old_revid = 'old-parent'
493
basis_shape = Inventory(root_id=None)
494
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
495
self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
496
self.add_dir(basis_shape, old_revid, 'dir-id-B', 'root-id', 'B')
497
self.add_link(basis_shape, old_revid, 'link-id-C', 'root-id', 'C', 'C')
498
self.add_link(basis_shape, old_revid, 'link-id-D', 'root-id', 'D', 'D')
499
self.add_file(basis_shape, old_revid, 'file-id-E', 'root-id', 'E',
501
self.add_file(basis_shape, old_revid, 'file-id-F', 'root-id', 'F',
503
new_revid = 'new-parent'
504
new_shape = Inventory(root_id=None)
505
self.add_new_root(new_shape, old_revid, new_revid)
506
self.add_dir(new_shape, new_revid, 'dir-id-A', 'root-id', 'B')
507
self.add_dir(new_shape, new_revid, 'dir-id-B', 'root-id', 'A')
508
self.add_link(new_shape, new_revid, 'link-id-C', 'root-id', 'D', 'C')
509
self.add_link(new_shape, new_revid, 'link-id-D', 'root-id', 'C', 'D')
510
self.add_file(new_shape, new_revid, 'file-id-E', 'root-id', 'F',
512
self.add_file(new_shape, new_revid, 'file-id-F', 'root-id', 'E',
514
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
515
new_shape, new_revid)
518
# test adding paths and dirs, including adding to a newly added dir.
519
old_revid = 'old-parent'
520
basis_shape = Inventory(root_id=None)
521
# with a root, so its a commit after the first.
522
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
523
new_revid = 'new-parent'
524
new_shape = Inventory(root_id=None)
525
self.add_new_root(new_shape, old_revid, new_revid)
526
self.add_dir(new_shape, new_revid, 'dir-id-A', 'root-id', 'A')
527
self.add_link(new_shape, new_revid, 'link-id-B', 'root-id', 'B', 'C')
528
self.add_file(new_shape, new_revid, 'file-id-C', 'root-id', 'C',
530
self.add_file(new_shape, new_revid, 'file-id-D', 'dir-id-A', 'D',
532
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
533
new_shape, new_revid)
535
def test_removes(self):
536
# test removing paths, including paths that are within other also
538
old_revid = 'old-parent'
539
basis_shape = Inventory(root_id=None)
540
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
541
self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
542
self.add_link(basis_shape, old_revid, 'link-id-B', 'root-id', 'B', 'C')
543
self.add_file(basis_shape, old_revid, 'file-id-C', 'root-id', 'C',
545
self.add_file(basis_shape, old_revid, 'file-id-D', 'dir-id-A', 'D',
547
new_revid = 'new-parent'
548
new_shape = Inventory(root_id=None)
549
self.add_new_root(new_shape, old_revid, new_revid)
550
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
551
new_shape, new_revid)
553
def test_move_to_added_dir(self):
554
old_revid = 'old-parent'
555
basis_shape = Inventory(root_id=None)
556
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
557
self.add_link(basis_shape, old_revid, 'link-id-B', 'root-id', 'B', 'C')
558
new_revid = 'new-parent'
559
new_shape = Inventory(root_id=None)
560
self.add_new_root(new_shape, old_revid, new_revid)
561
self.add_dir(new_shape, new_revid, 'dir-id-A', 'root-id', 'A')
562
self.add_link(new_shape, new_revid, 'link-id-B', 'dir-id-A', 'B', 'C')
563
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
564
new_shape, new_revid)
566
def test_move_from_removed_dir(self):
567
old_revid = 'old-parent'
568
basis_shape = Inventory(root_id=None)
569
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
570
self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
571
self.add_link(basis_shape, old_revid, 'link-id-B', 'dir-id-A', 'B', 'C')
572
new_revid = 'new-parent'
573
new_shape = Inventory(root_id=None)
574
self.add_new_root(new_shape, old_revid, new_revid)
575
self.add_link(new_shape, new_revid, 'link-id-B', 'root-id', 'B', 'C')
576
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
577
new_shape, new_revid)