2421
2426
self.assertTrue(len(statvalue) >= 10)
2422
2427
self.assertEqual(len(text), statvalue.st_size)
2423
2428
self.assertEqual(expected_sha, sha1)
2431
class _Repo(object):
2432
"""A minimal api to get InventoryRevisionTree to work."""
2435
default_format = bzrdir.format_registry.make_bzrdir('default')
2436
self._format = default_format.repository_format
2438
def lock_read(self):
2445
class TestUpdateBasisByDelta(tests.TestCase):
2447
def path_to_ie(self, path, file_id, rev_id, dir_ids):
2448
if path.endswith('/'):
2453
dirname, basename = osutils.split(path)
2455
dir_id = dir_ids[dirname]
2457
dir_id = osutils.basename(dirname) + '-id'
2459
ie = inventory.InventoryDirectory(file_id, basename, dir_id)
2460
dir_ids[path] = file_id
2462
ie = inventory.InventoryFile(file_id, basename, dir_id)
2465
ie.revision = rev_id
2468
def create_tree_from_shape(self, rev_id, shape):
2469
dir_ids = {'': 'root-id'}
2470
inv = inventory.Inventory('root-id', rev_id)
2471
for path, file_id in shape:
2473
# Replace the root entry
2474
del inv._byid[inv.root.file_id]
2475
inv.root.file_id = file_id
2476
inv._byid[file_id] = inv.root
2477
dir_ids[''] = file_id
2479
inv.add(self.path_to_ie(path, file_id, rev_id, dir_ids))
2480
return revisiontree.InventoryRevisionTree(_Repo(), inv, rev_id)
2482
def create_empty_dirstate(self):
2483
fd, path = tempfile.mkstemp(prefix='bzr-dirstate')
2484
self.addCleanup(os.remove, path)
2486
state = dirstate.DirState.initialize(path)
2487
self.addCleanup(state.unlock)
2490
def create_inv_delta(self, delta, rev_id):
2491
"""Translate a 'delta shape' into an actual InventoryDelta"""
2492
dir_ids = {'': 'root-id'}
2494
for old_path, new_path, file_id in delta:
2495
if old_path is not None and old_path.endswith('/'):
2496
# Don't have to actually do anything for this, because only
2497
# new_path creates InventoryEntries
2498
old_path = old_path[:-1]
2499
if new_path is None: # Delete
2500
inv_delta.append((old_path, None, file_id, None))
2502
ie = self.path_to_ie(new_path, file_id, rev_id, dir_ids)
2503
inv_delta.append((old_path, new_path, file_id, ie))
2506
def assertUpdate(self, active, basis, target):
2507
"""Assert that update_basis_by_delta works how we want.
2509
Set up a DirState object with active_shape for tree 0, basis_shape for
2510
tree 1. Then apply the delta from basis_shape to target_shape,
2511
and assert that the DirState is still valid, and that its stored
2512
content matches the target_shape.
2514
active_tree = self.create_tree_from_shape('active', active)
2515
basis_tree = self.create_tree_from_shape('basis', basis)
2516
target_tree = self.create_tree_from_shape('target', target)
2517
state = self.create_empty_dirstate()
2518
state.set_state_from_scratch(active_tree.inventory,
2519
[('basis', basis_tree)], [])
2520
delta = target_tree.inventory._make_delta(basis_tree.inventory)
2521
state.update_basis_by_delta(delta, 'target')
2523
dirstate_tree = workingtree_4.DirStateRevisionTree(state,
2525
# The target now that delta has been applied should match the
2527
self.assertEqual([], list(dirstate_tree.iter_changes(target_tree)))
2528
# And the dirblock state should be identical to the state if we created
2530
state2 = self.create_empty_dirstate()
2531
state2.set_state_from_scratch(active_tree.inventory,
2532
[('target', target_tree)], [])
2533
self.assertEqual(state2._dirblocks, state._dirblocks)
2536
def assertBadDelta(self, active, basis, delta):
2537
"""Test that we raise InconsistentDelta when appropriate.
2539
:param active: The active tree shape
2540
:param basis: The basis tree shape
2541
:param delta: A description of the delta to apply. Similar to the form
2542
for regular inventory deltas, but omitting the InventoryEntry.
2543
So adding a file is: (None, 'path', 'file-id')
2544
Adding a directory is: (None, 'path/', 'dir-id')
2545
Renaming a dir is: ('old/', 'new/', 'dir-id')
2548
active_tree = self.create_tree_from_shape('active', active)
2549
basis_tree = self.create_tree_from_shape('basis', basis)
2550
inv_delta = self.create_inv_delta(delta, 'target')
2551
state = self.create_empty_dirstate()
2552
state.set_state_from_scratch(active_tree.inventory,
2553
[('basis', basis_tree)], [])
2554
self.assertRaises(errors.InconsistentDelta,
2555
state.update_basis_by_delta, inv_delta, 'target')
2557
## state.update_basis_by_delta(inv_delta, 'target')
2558
## except errors.InconsistentDelta, e:
2559
## import pdb; pdb.set_trace()
2561
## import pdb; pdb.set_trace()
2562
self.assertTrue(state._changes_aborted)
2564
def test_remove_file_matching_active_state(self):
2565
state = self.assertUpdate(
2567
basis =[('file', 'file-id')],
2571
def test_remove_file_present_in_active_state(self):
2572
state = self.assertUpdate(
2573
active=[('file', 'file-id')],
2574
basis =[('file', 'file-id')],
2578
def test_remove_file_present_elsewhere_in_active_state(self):
2579
state = self.assertUpdate(
2580
active=[('other-file', 'file-id')],
2581
basis =[('file', 'file-id')],
2585
def test_remove_file_active_state_has_diff_file(self):
2586
state = self.assertUpdate(
2587
active=[('file', 'file-id-2')],
2588
basis =[('file', 'file-id')],
2592
def test_remove_file_active_state_has_diff_file_and_file_elsewhere(self):
2593
state = self.assertUpdate(
2594
active=[('file', 'file-id-2'),
2595
('other-file', 'file-id')],
2596
basis =[('file', 'file-id')],
2600
def test_add_file_matching_active_state(self):
2601
state = self.assertUpdate(
2602
active=[('file', 'file-id')],
2604
target=[('file', 'file-id')],
2607
def test_add_file_missing_in_active_state(self):
2608
state = self.assertUpdate(
2611
target=[('file', 'file-id')],
2614
def test_add_file_elsewhere_in_active_state(self):
2615
state = self.assertUpdate(
2616
active=[('other-file', 'file-id')],
2618
target=[('file', 'file-id')],
2621
def test_add_file_active_state_has_diff_file_and_file_elsewhere(self):
2622
state = self.assertUpdate(
2623
active=[('other-file', 'file-id'),
2624
('file', 'file-id-2')],
2626
target=[('file', 'file-id')],
2629
def test_rename_file_matching_active_state(self):
2630
state = self.assertUpdate(
2631
active=[('other-file', 'file-id')],
2632
basis =[('file', 'file-id')],
2633
target=[('other-file', 'file-id')],
2636
def test_rename_file_missing_in_active_state(self):
2637
state = self.assertUpdate(
2639
basis =[('file', 'file-id')],
2640
target=[('other-file', 'file-id')],
2643
def test_rename_file_present_elsewhere_in_active_state(self):
2644
state = self.assertUpdate(
2645
active=[('third', 'file-id')],
2646
basis =[('file', 'file-id')],
2647
target=[('other-file', 'file-id')],
2650
def test_rename_file_active_state_has_diff_source_file(self):
2651
state = self.assertUpdate(
2652
active=[('file', 'file-id-2')],
2653
basis =[('file', 'file-id')],
2654
target=[('other-file', 'file-id')],
2657
def test_rename_file_active_state_has_diff_target_file(self):
2658
state = self.assertUpdate(
2659
active=[('other-file', 'file-id-2')],
2660
basis =[('file', 'file-id')],
2661
target=[('other-file', 'file-id')],
2664
def test_rename_file_active_has_swapped_files(self):
2665
state = self.assertUpdate(
2666
active=[('file', 'file-id'),
2667
('other-file', 'file-id-2')],
2668
basis= [('file', 'file-id'),
2669
('other-file', 'file-id-2')],
2670
target=[('file', 'file-id-2'),
2671
('other-file', 'file-id')])
2673
def test_rename_file_basis_has_swapped_files(self):
2674
state = self.assertUpdate(
2675
active=[('file', 'file-id'),
2676
('other-file', 'file-id-2')],
2677
basis= [('file', 'file-id-2'),
2678
('other-file', 'file-id')],
2679
target=[('file', 'file-id'),
2680
('other-file', 'file-id-2')])
2682
def test_rename_directory_with_contents(self):
2683
state = self.assertUpdate( # active matches basis
2684
active=[('dir1/', 'dir-id'),
2685
('dir1/file', 'file-id')],
2686
basis= [('dir1/', 'dir-id'),
2687
('dir1/file', 'file-id')],
2688
target=[('dir2/', 'dir-id'),
2689
('dir2/file', 'file-id')])
2690
state = self.assertUpdate( # active matches target
2691
active=[('dir2/', 'dir-id'),
2692
('dir2/file', 'file-id')],
2693
basis= [('dir1/', 'dir-id'),
2694
('dir1/file', 'file-id')],
2695
target=[('dir2/', 'dir-id'),
2696
('dir2/file', 'file-id')])
2697
state = self.assertUpdate( # active empty
2699
basis= [('dir1/', 'dir-id'),
2700
('dir1/file', 'file-id')],
2701
target=[('dir2/', 'dir-id'),
2702
('dir2/file', 'file-id')])
2703
state = self.assertUpdate( # active present at other location
2704
active=[('dir3/', 'dir-id'),
2705
('dir3/file', 'file-id')],
2706
basis= [('dir1/', 'dir-id'),
2707
('dir1/file', 'file-id')],
2708
target=[('dir2/', 'dir-id'),
2709
('dir2/file', 'file-id')])
2710
state = self.assertUpdate( # active has different ids
2711
active=[('dir1/', 'dir1-id'),
2712
('dir1/file', 'file1-id'),
2713
('dir2/', 'dir2-id'),
2714
('dir2/file', 'file2-id')],
2715
basis= [('dir1/', 'dir-id'),
2716
('dir1/file', 'file-id')],
2717
target=[('dir2/', 'dir-id'),
2718
('dir2/file', 'file-id')])
2720
def test_invalid_file_not_present(self):
2721
state = self.assertBadDelta(
2722
active=[('file', 'file-id')],
2723
basis= [('file', 'file-id')],
2724
delta=[('other-file', 'file', 'file-id')])
2726
def test_invalid_new_id_same_path(self):
2727
# The bad entry comes after
2728
state = self.assertBadDelta(
2729
active=[('file', 'file-id')],
2730
basis= [('file', 'file-id')],
2731
delta=[(None, 'file', 'file-id-2')])
2732
# The bad entry comes first
2733
state = self.assertBadDelta(
2734
active=[('file', 'file-id-2')],
2735
basis=[('file', 'file-id-2')],
2736
delta=[(None, 'file', 'file-id')])
2738
def test_invalid_existing_id(self):
2739
state = self.assertBadDelta(
2740
active=[('file', 'file-id')],
2741
basis= [('file', 'file-id')],
2742
delta=[(None, 'file', 'file-id')])
2744
def test_invalid_parent_missing(self):
2745
state = self.assertBadDelta(
2748
delta=[(None, 'path/path2', 'file-id')])
2749
# Note: we force the active tree to have the directory, by knowing how
2750
# path_to_ie handles entries with missing parents
2751
state = self.assertBadDelta(
2752
active=[('path/', 'path-id')],
2754
delta=[(None, 'path/path2', 'file-id')])
2755
state = self.assertBadDelta(
2756
active=[('path/', 'path-id'),
2757
('path/path2', 'file-id')],
2759
delta=[(None, 'path/path2', 'file-id')])
2761
def test_renamed_dir_same_path(self):
2762
# We replace the parent directory, with another parent dir. But the C
2763
# file doesn't look like it has been moved.
2764
state = self.assertUpdate(# Same as basis
2765
active=[('dir/', 'A-id'),
2767
basis= [('dir/', 'A-id'),
2769
target=[('dir/', 'C-id'),
2771
state = self.assertUpdate(# Same as target
2772
active=[('dir/', 'C-id'),
2774
basis= [('dir/', 'A-id'),
2776
target=[('dir/', 'C-id'),
2778
state = self.assertUpdate(# empty active
2780
basis= [('dir/', 'A-id'),
2782
target=[('dir/', 'C-id'),
2784
state = self.assertUpdate(# different active
2785
active=[('dir/', 'D-id'),
2787
basis= [('dir/', 'A-id'),
2789
target=[('dir/', 'C-id'),
2792
def test_parent_child_swap(self):
2793
state = self.assertUpdate(# Same as basis
2794
active=[('A/', 'A-id'),
2797
basis= [('A/', 'A-id'),
2800
target=[('A/', 'B-id'),
2803
state = self.assertUpdate(# Same as target
2804
active=[('A/', 'B-id'),
2807
basis= [('A/', 'A-id'),
2810
target=[('A/', 'B-id'),
2813
state = self.assertUpdate(# empty active
2815
basis= [('A/', 'A-id'),
2818
target=[('A/', 'B-id'),
2821
state = self.assertUpdate(# different active
2822
active=[('D/', 'A-id'),
2825
basis= [('A/', 'A-id'),
2828
target=[('A/', 'B-id'),
2832
def test_change_root_id(self):
2833
state = self.assertUpdate( # same as basis
2834
active=[('', 'root-id'),
2835
('file', 'file-id')],
2836
basis= [('', 'root-id'),
2837
('file', 'file-id')],
2838
target=[('', 'target-root-id'),
2839
('file', 'file-id')])
2840
state = self.assertUpdate( # same as target
2841
active=[('', 'target-root-id'),
2842
('file', 'file-id')],
2843
basis= [('', 'root-id'),
2844
('file', 'file-id')],
2845
target=[('', 'target-root-id'),
2846
('file', 'root-id')])
2847
state = self.assertUpdate( # all different
2848
active=[('', 'active-root-id'),
2849
('file', 'file-id')],
2850
basis= [('', 'root-id'),
2851
('file', 'file-id')],
2852
target=[('', 'target-root-id'),
2853
('file', 'root-id')])
2855
def test_change_file_absent_in_active(self):
2856
state = self.assertUpdate(
2858
basis= [('file', 'file-id')],
2859
target=[('file', 'file-id')])
2861
def test_invalid_changed_file(self):
2862
state = self.assertBadDelta( # Not present in basis
2863
active=[('file', 'file-id')],
2865
delta=[('file', 'file', 'file-id')])
2866
state = self.assertBadDelta( # present at another location in basis
2867
active=[('file', 'file-id')],
2868
basis= [('other-file', 'file-id')],
2869
delta=[('file', 'file', 'file-id')])