2421
2435
self.assertTrue(len(statvalue) >= 10)
2422
2436
self.assertEqual(len(text), statvalue.st_size)
2423
2437
self.assertEqual(expected_sha, sha1)
2440
class _Repo(object):
2441
"""A minimal api to get InventoryRevisionTree to work."""
2444
default_format = bzrdir.format_registry.make_bzrdir('default')
2445
self._format = default_format.repository_format
2447
def lock_read(self):
2454
class TestUpdateBasisByDelta(tests.TestCase):
2456
def path_to_ie(self, path, file_id, rev_id, dir_ids):
2457
if path.endswith('/'):
2462
dirname, basename = osutils.split(path)
2464
dir_id = dir_ids[dirname]
2466
dir_id = osutils.basename(dirname) + '-id'
2468
ie = inventory.InventoryDirectory(file_id, basename, dir_id)
2469
dir_ids[path] = file_id
2471
ie = inventory.InventoryFile(file_id, basename, dir_id)
2474
ie.revision = rev_id
2477
def create_tree_from_shape(self, rev_id, shape):
2478
dir_ids = {'': 'root-id'}
2479
inv = inventory.Inventory('root-id', rev_id)
2480
for path, file_id in shape:
2482
# Replace the root entry
2483
del inv._byid[inv.root.file_id]
2484
inv.root.file_id = file_id
2485
inv._byid[file_id] = inv.root
2486
dir_ids[''] = file_id
2488
inv.add(self.path_to_ie(path, file_id, rev_id, dir_ids))
2489
return revisiontree.InventoryRevisionTree(_Repo(), inv, rev_id)
2491
def create_empty_dirstate(self):
2492
fd, path = tempfile.mkstemp(prefix='bzr-dirstate')
2493
self.addCleanup(os.remove, path)
2495
state = dirstate.DirState.initialize(path)
2496
self.addCleanup(state.unlock)
2499
def create_inv_delta(self, delta, rev_id):
2500
"""Translate a 'delta shape' into an actual InventoryDelta"""
2501
dir_ids = {'': 'root-id'}
2503
for old_path, new_path, file_id in delta:
2504
if old_path is not None and old_path.endswith('/'):
2505
# Don't have to actually do anything for this, because only
2506
# new_path creates InventoryEntries
2507
old_path = old_path[:-1]
2508
if new_path is None: # Delete
2509
inv_delta.append((old_path, None, file_id, None))
2511
ie = self.path_to_ie(new_path, file_id, rev_id, dir_ids)
2512
inv_delta.append((old_path, new_path, file_id, ie))
2515
def assertUpdate(self, active, basis, target):
2516
"""Assert that update_basis_by_delta works how we want.
2518
Set up a DirState object with active_shape for tree 0, basis_shape for
2519
tree 1. Then apply the delta from basis_shape to target_shape,
2520
and assert that the DirState is still valid, and that its stored
2521
content matches the target_shape.
2523
active_tree = self.create_tree_from_shape('active', active)
2524
basis_tree = self.create_tree_from_shape('basis', basis)
2525
target_tree = self.create_tree_from_shape('target', target)
2526
state = self.create_empty_dirstate()
2527
state.set_state_from_scratch(active_tree.inventory,
2528
[('basis', basis_tree)], [])
2529
delta = target_tree.inventory._make_delta(basis_tree.inventory)
2530
state.update_basis_by_delta(delta, 'target')
2532
dirstate_tree = workingtree_4.DirStateRevisionTree(state,
2534
# The target now that delta has been applied should match the
2536
self.assertEqual([], list(dirstate_tree.iter_changes(target_tree)))
2537
# And the dirblock state should be identical to the state if we created
2539
state2 = self.create_empty_dirstate()
2540
state2.set_state_from_scratch(active_tree.inventory,
2541
[('target', target_tree)], [])
2542
self.assertEqual(state2._dirblocks, state._dirblocks)
2545
def assertBadDelta(self, active, basis, delta):
2546
"""Test that we raise InconsistentDelta when appropriate.
2548
:param active: The active tree shape
2549
:param basis: The basis tree shape
2550
:param delta: A description of the delta to apply. Similar to the form
2551
for regular inventory deltas, but omitting the InventoryEntry.
2552
So adding a file is: (None, 'path', 'file-id')
2553
Adding a directory is: (None, 'path/', 'dir-id')
2554
Renaming a dir is: ('old/', 'new/', 'dir-id')
2557
active_tree = self.create_tree_from_shape('active', active)
2558
basis_tree = self.create_tree_from_shape('basis', basis)
2559
inv_delta = self.create_inv_delta(delta, 'target')
2560
state = self.create_empty_dirstate()
2561
state.set_state_from_scratch(active_tree.inventory,
2562
[('basis', basis_tree)], [])
2563
self.assertRaises(errors.InconsistentDelta,
2564
state.update_basis_by_delta, inv_delta, 'target')
2566
## state.update_basis_by_delta(inv_delta, 'target')
2567
## except errors.InconsistentDelta, e:
2568
## import pdb; pdb.set_trace()
2570
## import pdb; pdb.set_trace()
2571
self.assertTrue(state._changes_aborted)
2573
def test_remove_file_matching_active_state(self):
2574
state = self.assertUpdate(
2576
basis =[('file', 'file-id')],
2580
def test_remove_file_present_in_active_state(self):
2581
state = self.assertUpdate(
2582
active=[('file', 'file-id')],
2583
basis =[('file', 'file-id')],
2587
def test_remove_file_present_elsewhere_in_active_state(self):
2588
state = self.assertUpdate(
2589
active=[('other-file', 'file-id')],
2590
basis =[('file', 'file-id')],
2594
def test_remove_file_active_state_has_diff_file(self):
2595
state = self.assertUpdate(
2596
active=[('file', 'file-id-2')],
2597
basis =[('file', 'file-id')],
2601
def test_remove_file_active_state_has_diff_file_and_file_elsewhere(self):
2602
state = self.assertUpdate(
2603
active=[('file', 'file-id-2'),
2604
('other-file', 'file-id')],
2605
basis =[('file', 'file-id')],
2609
def test_add_file_matching_active_state(self):
2610
state = self.assertUpdate(
2611
active=[('file', 'file-id')],
2613
target=[('file', 'file-id')],
2616
def test_add_file_missing_in_active_state(self):
2617
state = self.assertUpdate(
2620
target=[('file', 'file-id')],
2623
def test_add_file_elsewhere_in_active_state(self):
2624
state = self.assertUpdate(
2625
active=[('other-file', 'file-id')],
2627
target=[('file', 'file-id')],
2630
def test_add_file_active_state_has_diff_file_and_file_elsewhere(self):
2631
state = self.assertUpdate(
2632
active=[('other-file', 'file-id'),
2633
('file', 'file-id-2')],
2635
target=[('file', 'file-id')],
2638
def test_rename_file_matching_active_state(self):
2639
state = self.assertUpdate(
2640
active=[('other-file', 'file-id')],
2641
basis =[('file', 'file-id')],
2642
target=[('other-file', 'file-id')],
2645
def test_rename_file_missing_in_active_state(self):
2646
state = self.assertUpdate(
2648
basis =[('file', 'file-id')],
2649
target=[('other-file', 'file-id')],
2652
def test_rename_file_present_elsewhere_in_active_state(self):
2653
state = self.assertUpdate(
2654
active=[('third', 'file-id')],
2655
basis =[('file', 'file-id')],
2656
target=[('other-file', 'file-id')],
2659
def test_rename_file_active_state_has_diff_source_file(self):
2660
state = self.assertUpdate(
2661
active=[('file', 'file-id-2')],
2662
basis =[('file', 'file-id')],
2663
target=[('other-file', 'file-id')],
2666
def test_rename_file_active_state_has_diff_target_file(self):
2667
state = self.assertUpdate(
2668
active=[('other-file', 'file-id-2')],
2669
basis =[('file', 'file-id')],
2670
target=[('other-file', 'file-id')],
2673
def test_rename_file_active_has_swapped_files(self):
2674
state = self.assertUpdate(
2675
active=[('file', 'file-id'),
2676
('other-file', 'file-id-2')],
2677
basis= [('file', 'file-id'),
2678
('other-file', 'file-id-2')],
2679
target=[('file', 'file-id-2'),
2680
('other-file', 'file-id')])
2682
def test_rename_file_basis_has_swapped_files(self):
2683
state = self.assertUpdate(
2684
active=[('file', 'file-id'),
2685
('other-file', 'file-id-2')],
2686
basis= [('file', 'file-id-2'),
2687
('other-file', 'file-id')],
2688
target=[('file', 'file-id'),
2689
('other-file', 'file-id-2')])
2691
def test_rename_directory_with_contents(self):
2692
state = self.assertUpdate( # active matches basis
2693
active=[('dir1/', 'dir-id'),
2694
('dir1/file', 'file-id')],
2695
basis= [('dir1/', 'dir-id'),
2696
('dir1/file', 'file-id')],
2697
target=[('dir2/', 'dir-id'),
2698
('dir2/file', 'file-id')])
2699
state = self.assertUpdate( # active matches target
2700
active=[('dir2/', 'dir-id'),
2701
('dir2/file', 'file-id')],
2702
basis= [('dir1/', 'dir-id'),
2703
('dir1/file', 'file-id')],
2704
target=[('dir2/', 'dir-id'),
2705
('dir2/file', 'file-id')])
2706
state = self.assertUpdate( # active empty
2708
basis= [('dir1/', 'dir-id'),
2709
('dir1/file', 'file-id')],
2710
target=[('dir2/', 'dir-id'),
2711
('dir2/file', 'file-id')])
2712
state = self.assertUpdate( # active present at other location
2713
active=[('dir3/', 'dir-id'),
2714
('dir3/file', 'file-id')],
2715
basis= [('dir1/', 'dir-id'),
2716
('dir1/file', 'file-id')],
2717
target=[('dir2/', 'dir-id'),
2718
('dir2/file', 'file-id')])
2719
state = self.assertUpdate( # active has different ids
2720
active=[('dir1/', 'dir1-id'),
2721
('dir1/file', 'file1-id'),
2722
('dir2/', 'dir2-id'),
2723
('dir2/file', 'file2-id')],
2724
basis= [('dir1/', 'dir-id'),
2725
('dir1/file', 'file-id')],
2726
target=[('dir2/', 'dir-id'),
2727
('dir2/file', 'file-id')])
2729
def test_invalid_file_not_present(self):
2730
state = self.assertBadDelta(
2731
active=[('file', 'file-id')],
2732
basis= [('file', 'file-id')],
2733
delta=[('other-file', 'file', 'file-id')])
2735
def test_invalid_new_id_same_path(self):
2736
# The bad entry comes after
2737
state = self.assertBadDelta(
2738
active=[('file', 'file-id')],
2739
basis= [('file', 'file-id')],
2740
delta=[(None, 'file', 'file-id-2')])
2741
# The bad entry comes first
2742
state = self.assertBadDelta(
2743
active=[('file', 'file-id-2')],
2744
basis=[('file', 'file-id-2')],
2745
delta=[(None, 'file', 'file-id')])
2747
def test_invalid_existing_id(self):
2748
state = self.assertBadDelta(
2749
active=[('file', 'file-id')],
2750
basis= [('file', 'file-id')],
2751
delta=[(None, 'file', 'file-id')])
2753
def test_invalid_parent_missing(self):
2754
state = self.assertBadDelta(
2757
delta=[(None, 'path/path2', 'file-id')])
2758
# Note: we force the active tree to have the directory, by knowing how
2759
# path_to_ie handles entries with missing parents
2760
state = self.assertBadDelta(
2761
active=[('path/', 'path-id')],
2763
delta=[(None, 'path/path2', 'file-id')])
2764
state = self.assertBadDelta(
2765
active=[('path/', 'path-id'),
2766
('path/path2', 'file-id')],
2768
delta=[(None, 'path/path2', 'file-id')])
2770
def test_renamed_dir_same_path(self):
2771
# We replace the parent directory, with another parent dir. But the C
2772
# file doesn't look like it has been moved.
2773
state = self.assertUpdate(# Same as basis
2774
active=[('dir/', 'A-id'),
2776
basis= [('dir/', 'A-id'),
2778
target=[('dir/', 'C-id'),
2780
state = self.assertUpdate(# Same as target
2781
active=[('dir/', 'C-id'),
2783
basis= [('dir/', 'A-id'),
2785
target=[('dir/', 'C-id'),
2787
state = self.assertUpdate(# empty active
2789
basis= [('dir/', 'A-id'),
2791
target=[('dir/', 'C-id'),
2793
state = self.assertUpdate(# different active
2794
active=[('dir/', 'D-id'),
2796
basis= [('dir/', 'A-id'),
2798
target=[('dir/', 'C-id'),
2801
def test_parent_child_swap(self):
2802
state = self.assertUpdate(# Same as basis
2803
active=[('A/', 'A-id'),
2806
basis= [('A/', 'A-id'),
2809
target=[('A/', 'B-id'),
2812
state = self.assertUpdate(# Same as target
2813
active=[('A/', 'B-id'),
2816
basis= [('A/', 'A-id'),
2819
target=[('A/', 'B-id'),
2822
state = self.assertUpdate(# empty active
2824
basis= [('A/', 'A-id'),
2827
target=[('A/', 'B-id'),
2830
state = self.assertUpdate(# different active
2831
active=[('D/', 'A-id'),
2834
basis= [('A/', 'A-id'),
2837
target=[('A/', 'B-id'),
2841
def test_change_root_id(self):
2842
state = self.assertUpdate( # same as basis
2843
active=[('', 'root-id'),
2844
('file', 'file-id')],
2845
basis= [('', 'root-id'),
2846
('file', 'file-id')],
2847
target=[('', 'target-root-id'),
2848
('file', 'file-id')])
2849
state = self.assertUpdate( # same as target
2850
active=[('', 'target-root-id'),
2851
('file', 'file-id')],
2852
basis= [('', 'root-id'),
2853
('file', 'file-id')],
2854
target=[('', 'target-root-id'),
2855
('file', 'root-id')])
2856
state = self.assertUpdate( # all different
2857
active=[('', 'active-root-id'),
2858
('file', 'file-id')],
2859
basis= [('', 'root-id'),
2860
('file', 'file-id')],
2861
target=[('', 'target-root-id'),
2862
('file', 'root-id')])
2864
def test_change_file_absent_in_active(self):
2865
state = self.assertUpdate(
2867
basis= [('file', 'file-id')],
2868
target=[('file', 'file-id')])
2870
def test_invalid_changed_file(self):
2871
state = self.assertBadDelta( # Not present in basis
2872
active=[('file', 'file-id')],
2874
delta=[('file', 'file', 'file-id')])
2875
state = self.assertBadDelta( # present at another location in basis
2876
active=[('file', 'file-id')],
2877
basis= [('other-file', 'file-id')],
2878
delta=[('file', 'file', 'file-id')])