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
delta = self.make_inv_delta(basis_shape, new_shape)
344
tree = self.make_branch_and_tree('tree')
345
# the shapes need to be in the tree's repository to be able to set them
346
# as a parent, but the file content is not needed.
347
if basis_revid is not None:
348
self.fake_up_revision(tree, basis_revid, basis_shape)
349
parents = [basis_revid]
350
if extra_parent is not None:
351
parents.append(extra_parent)
352
tree.set_parent_ids(parents)
353
self.fake_up_revision(tree, new_revid, new_shape)
354
self.assertDeltaApplicationResultsInExpectedBasis(tree, new_revid,
356
osutils.rmtree('tree')
358
def test_no_parents_just_root(self):
359
"""Test doing an empty commit - no parent, set a root only."""
360
basis_shape = Inventory(root_id=None) # empty tree
361
new_shape = Inventory() # tree with a root
362
self.assertTransitionFromBasisToShape(basis_shape, None, new_shape,
365
def test_no_parents_full_tree(self):
366
"""Test doing a regular initial commit with files and dirs."""
367
basis_shape = Inventory(root_id=None) # empty tree
369
new_shape = Inventory(root_id=None)
370
self.add_dir(new_shape, revid, 'root-id', None, '')
371
self.add_link(new_shape, revid, 'link-id', 'root-id', 'link', 'target')
372
self.add_file(new_shape, revid, 'file-id', 'root-id', 'file', '1' * 32,
374
self.add_dir(new_shape, revid, 'dir-id', 'root-id', 'dir')
375
self.add_file(new_shape, revid, 'subfile-id', 'dir-id', 'subfile',
377
self.assertTransitionFromBasisToShape(basis_shape, None, new_shape,
380
def test_file_content_change(self):
381
old_revid = 'old-parent'
382
basis_shape = Inventory(root_id=None)
383
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
384
self.add_file(basis_shape, old_revid, 'file-id', 'root-id', 'file',
386
new_revid = 'new-parent'
387
new_shape = Inventory(root_id=None)
388
self.add_new_root(new_shape, old_revid, new_revid)
389
self.add_file(new_shape, new_revid, 'file-id', 'root-id', 'file',
391
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
392
new_shape, new_revid)
394
def test_link_content_change(self):
395
old_revid = 'old-parent'
396
basis_shape = Inventory(root_id=None)
397
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
398
self.add_link(basis_shape, old_revid, 'link-id', 'root-id', 'link',
400
new_revid = 'new-parent'
401
new_shape = Inventory(root_id=None)
402
self.add_new_root(new_shape, old_revid, new_revid)
403
self.add_link(new_shape, new_revid, 'link-id', 'root-id', 'link',
405
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
406
new_shape, new_revid)
408
def test_kind_changes(self):
409
def do_file(inv, revid):
410
self.add_file(inv, revid, 'path-id', 'root-id', 'path', '1' * 32,
412
def do_link(inv, revid):
413
self.add_link(inv, revid, 'path-id', 'root-id', 'path', 'target')
414
def do_dir(inv, revid):
415
self.add_dir(inv, revid, 'path-id', 'root-id', 'path')
416
for old_factory in (do_file, do_link, do_dir):
417
for new_factory in (do_file, do_link, do_dir):
418
if old_factory == new_factory:
420
old_revid = 'old-parent'
421
basis_shape = Inventory(root_id=None)
422
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
423
old_factory(basis_shape, old_revid)
424
new_revid = 'new-parent'
425
new_shape = Inventory(root_id=None)
426
self.add_new_root(new_shape, old_revid, new_revid)
427
new_factory(new_shape, new_revid)
428
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
429
new_shape, new_revid)
431
def test_content_from_second_parent_is_dropped(self):
432
left_revid = 'left-parent'
433
basis_shape = Inventory(root_id=None)
434
self.add_dir(basis_shape, left_revid, 'root-id', None, '')
435
self.add_link(basis_shape, left_revid, 'link-id', 'root-id', 'link',
437
# the right shape has content - file, link, subdir with a child,
438
# that should all be discarded by the call.
439
right_revid = 'right-parent'
440
right_shape = Inventory(root_id=None)
441
self.add_dir(right_shape, left_revid, 'root-id', None, '')
442
self.add_link(right_shape, right_revid, 'link-id', 'root-id', 'link',
444
self.add_dir(right_shape, right_revid, 'subdir-id', 'root-id', 'dir')
445
self.add_file(right_shape, right_revid, 'file-id', 'subdir-id', 'file',
447
new_revid = 'new-parent'
448
new_shape = Inventory(root_id=None)
449
self.add_new_root(new_shape, left_revid, new_revid)
450
self.add_link(new_shape, new_revid, 'link-id', 'root-id', 'link',
452
self.assertTransitionFromBasisToShape(basis_shape, left_revid,
453
new_shape, new_revid, right_revid)
455
def test_parent_id_changed(self):
456
# test that when the only change to an entry is its parent id changing
457
# that it is handled correctly (that is it keeps the same path)
458
old_revid = 'old-parent'
459
basis_shape = Inventory(root_id=None)
460
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
461
self.add_dir(basis_shape, old_revid, 'orig-parent-id', 'root-id', 'dir')
462
self.add_dir(basis_shape, old_revid, 'dir-id', 'orig-parent-id', 'dir')
463
new_revid = 'new-parent'
464
new_shape = Inventory(root_id=None)
465
self.add_new_root(new_shape, old_revid, new_revid)
466
self.add_dir(new_shape, new_revid, 'new-parent-id', 'root-id', 'dir')
467
self.add_dir(new_shape, new_revid, 'dir-id', 'new-parent-id', 'dir')
468
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
469
new_shape, new_revid)
471
def test_name_changed(self):
472
# test that when the only change to an entry is its name changing that
473
# it is handled correctly (that is it keeps the same parent id)
474
old_revid = 'old-parent'
475
basis_shape = Inventory(root_id=None)
476
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
477
self.add_dir(basis_shape, old_revid, 'parent-id', 'root-id', 'origdir')
478
self.add_dir(basis_shape, old_revid, 'dir-id', 'parent-id', 'olddir')
479
new_revid = 'new-parent'
480
new_shape = Inventory(root_id=None)
481
self.add_new_root(new_shape, old_revid, new_revid)
482
self.add_dir(new_shape, new_revid, 'parent-id', 'root-id', 'newdir')
483
self.add_dir(new_shape, new_revid, 'dir-id', 'parent-id', 'newdir')
484
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
485
new_shape, new_revid)
487
def test_path_swap(self):
488
# test a A->B and B->A path swap.
489
old_revid = 'old-parent'
490
basis_shape = Inventory(root_id=None)
491
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
492
self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
493
self.add_dir(basis_shape, old_revid, 'dir-id-B', 'root-id', 'B')
494
self.add_link(basis_shape, old_revid, 'link-id-C', 'root-id', 'C', 'C')
495
self.add_link(basis_shape, old_revid, 'link-id-D', 'root-id', 'D', 'D')
496
self.add_file(basis_shape, old_revid, 'file-id-E', 'root-id', 'E',
498
self.add_file(basis_shape, old_revid, 'file-id-F', 'root-id', 'F',
500
new_revid = 'new-parent'
501
new_shape = Inventory(root_id=None)
502
self.add_new_root(new_shape, old_revid, new_revid)
503
self.add_dir(new_shape, new_revid, 'dir-id-A', 'root-id', 'B')
504
self.add_dir(new_shape, new_revid, 'dir-id-B', 'root-id', 'A')
505
self.add_link(new_shape, new_revid, 'link-id-C', 'root-id', 'D', 'C')
506
self.add_link(new_shape, new_revid, 'link-id-D', 'root-id', 'C', 'D')
507
self.add_file(new_shape, new_revid, 'file-id-E', 'root-id', 'F',
509
self.add_file(new_shape, new_revid, 'file-id-F', 'root-id', 'E',
511
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
512
new_shape, new_revid)
515
# test adding paths and dirs, including adding to a newly added dir.
516
old_revid = 'old-parent'
517
basis_shape = Inventory(root_id=None)
518
# with a root, so its a commit after the first.
519
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
520
new_revid = 'new-parent'
521
new_shape = Inventory(root_id=None)
522
self.add_new_root(new_shape, old_revid, new_revid)
523
self.add_dir(new_shape, new_revid, 'dir-id-A', 'root-id', 'A')
524
self.add_link(new_shape, new_revid, 'link-id-B', 'root-id', 'B', 'C')
525
self.add_file(new_shape, new_revid, 'file-id-C', 'root-id', 'C',
527
self.add_file(new_shape, new_revid, 'file-id-D', 'dir-id-A', 'D',
529
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
530
new_shape, new_revid)
532
def test_removes(self):
533
# test removing paths, including paths that are within other also
535
old_revid = 'old-parent'
536
basis_shape = Inventory(root_id=None)
537
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
538
self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
539
self.add_link(basis_shape, old_revid, 'link-id-B', 'root-id', 'B', 'C')
540
self.add_file(basis_shape, old_revid, 'file-id-C', 'root-id', 'C',
542
self.add_file(basis_shape, old_revid, 'file-id-D', 'dir-id-A', 'D',
544
new_revid = 'new-parent'
545
new_shape = Inventory(root_id=None)
546
self.add_new_root(new_shape, old_revid, new_revid)
547
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
548
new_shape, new_revid)
550
def test_move_to_added_dir(self):
551
old_revid = 'old-parent'
552
basis_shape = Inventory(root_id=None)
553
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
554
self.add_link(basis_shape, old_revid, 'link-id-B', 'root-id', 'B', 'C')
555
new_revid = 'new-parent'
556
new_shape = Inventory(root_id=None)
557
self.add_new_root(new_shape, old_revid, new_revid)
558
self.add_dir(new_shape, new_revid, 'dir-id-A', 'root-id', 'A')
559
self.add_link(new_shape, new_revid, 'link-id-B', 'dir-id-A', 'B', 'C')
560
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
561
new_shape, new_revid)
563
def test_move_from_removed_dir(self):
564
old_revid = 'old-parent'
565
basis_shape = Inventory(root_id=None)
566
self.add_dir(basis_shape, old_revid, 'root-id', None, '')
567
self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
568
self.add_link(basis_shape, old_revid, 'link-id-B', 'dir-id-A', 'B', 'C')
569
new_revid = 'new-parent'
570
new_shape = Inventory(root_id=None)
571
self.add_new_root(new_shape, old_revid, new_revid)
572
self.add_link(new_shape, new_revid, 'link-id-B', 'root-id', 'B', 'C')
573
self.assertTransitionFromBasisToShape(basis_shape, old_revid,
574
new_shape, new_revid)