2320
2439
self.assertTrue(len(statvalue) >= 10)
2321
2440
self.assertEqual(len(text), statvalue.st_size)
2322
2441
self.assertEqual(expected_sha, sha1)
2444
class _Repo(object):
2445
"""A minimal api to get InventoryRevisionTree to work."""
2448
default_format = controldir.format_registry.make_controldir('default')
2449
self._format = default_format.repository_format
2451
def lock_read(self):
2458
class TestUpdateBasisByDelta(tests.TestCase):
2460
def path_to_ie(self, path, file_id, rev_id, dir_ids):
2461
if path.endswith('/'):
2466
dirname, basename = osutils.split(path)
2468
dir_id = dir_ids[dirname]
2470
dir_id = osutils.basename(dirname) + '-id'
2472
ie = inventory.InventoryDirectory(file_id, basename, dir_id)
2473
dir_ids[path] = file_id
2475
ie = inventory.InventoryFile(file_id, basename, dir_id)
2478
ie.revision = rev_id
2481
def create_tree_from_shape(self, rev_id, shape):
2482
dir_ids = {'': 'root-id'}
2483
inv = inventory.Inventory('root-id', rev_id)
2486
path, file_id = info
2489
path, file_id, ie_rev_id = info
2491
# Replace the root entry
2492
del inv._byid[inv.root.file_id]
2493
inv.root.file_id = file_id
2494
inv._byid[file_id] = inv.root
2495
dir_ids[''] = file_id
2497
inv.add(self.path_to_ie(path, file_id, ie_rev_id, dir_ids))
2498
return inventorytree.InventoryRevisionTree(_Repo(), inv, rev_id)
2500
def create_empty_dirstate(self):
2501
fd, path = tempfile.mkstemp(prefix='bzr-dirstate')
2502
self.addCleanup(os.remove, path)
2504
state = dirstate.DirState.initialize(path)
2505
self.addCleanup(state.unlock)
2508
def create_inv_delta(self, delta, rev_id):
2509
"""Translate a 'delta shape' into an actual InventoryDelta"""
2510
dir_ids = {'': 'root-id'}
2512
for old_path, new_path, file_id in delta:
2513
if old_path is not None and old_path.endswith('/'):
2514
# Don't have to actually do anything for this, because only
2515
# new_path creates InventoryEntries
2516
old_path = old_path[:-1]
2517
if new_path is None: # Delete
2518
inv_delta.append((old_path, None, file_id, None))
2520
ie = self.path_to_ie(new_path, file_id, rev_id, dir_ids)
2521
inv_delta.append((old_path, new_path, file_id, ie))
2524
def assertUpdate(self, active, basis, target):
2525
"""Assert that update_basis_by_delta works how we want.
2527
Set up a DirState object with active_shape for tree 0, basis_shape for
2528
tree 1. Then apply the delta from basis_shape to target_shape,
2529
and assert that the DirState is still valid, and that its stored
2530
content matches the target_shape.
2532
active_tree = self.create_tree_from_shape('active', active)
2533
basis_tree = self.create_tree_from_shape('basis', basis)
2534
target_tree = self.create_tree_from_shape('target', target)
2535
state = self.create_empty_dirstate()
2536
state.set_state_from_scratch(active_tree.root_inventory,
2537
[('basis', basis_tree)], [])
2538
delta = target_tree.root_inventory._make_delta(
2539
basis_tree.root_inventory)
2540
state.update_basis_by_delta(delta, 'target')
2542
dirstate_tree = workingtree_4.DirStateRevisionTree(state,
2544
# The target now that delta has been applied should match the
2546
self.assertEqual([], list(dirstate_tree.iter_changes(target_tree)))
2547
# And the dirblock state should be identical to the state if we created
2549
state2 = self.create_empty_dirstate()
2550
state2.set_state_from_scratch(active_tree.root_inventory,
2551
[('target', target_tree)], [])
2552
self.assertEqual(state2._dirblocks, state._dirblocks)
2555
def assertBadDelta(self, active, basis, delta):
2556
"""Test that we raise InconsistentDelta when appropriate.
2558
:param active: The active tree shape
2559
:param basis: The basis tree shape
2560
:param delta: A description of the delta to apply. Similar to the form
2561
for regular inventory deltas, but omitting the InventoryEntry.
2562
So adding a file is: (None, 'path', 'file-id')
2563
Adding a directory is: (None, 'path/', 'dir-id')
2564
Renaming a dir is: ('old/', 'new/', 'dir-id')
2567
active_tree = self.create_tree_from_shape('active', active)
2568
basis_tree = self.create_tree_from_shape('basis', basis)
2569
inv_delta = self.create_inv_delta(delta, 'target')
2570
state = self.create_empty_dirstate()
2571
state.set_state_from_scratch(active_tree.root_inventory,
2572
[('basis', basis_tree)], [])
2573
self.assertRaises(errors.InconsistentDelta,
2574
state.update_basis_by_delta, inv_delta, 'target')
2576
## state.update_basis_by_delta(inv_delta, 'target')
2577
## except errors.InconsistentDelta, e:
2578
## import pdb; pdb.set_trace()
2580
## import pdb; pdb.set_trace()
2581
self.assertTrue(state._changes_aborted)
2583
def test_remove_file_matching_active_state(self):
2584
state = self.assertUpdate(
2586
basis =[('file', 'file-id')],
2590
def test_remove_file_present_in_active_state(self):
2591
state = self.assertUpdate(
2592
active=[('file', 'file-id')],
2593
basis =[('file', 'file-id')],
2597
def test_remove_file_present_elsewhere_in_active_state(self):
2598
state = self.assertUpdate(
2599
active=[('other-file', 'file-id')],
2600
basis =[('file', 'file-id')],
2604
def test_remove_file_active_state_has_diff_file(self):
2605
state = self.assertUpdate(
2606
active=[('file', 'file-id-2')],
2607
basis =[('file', 'file-id')],
2611
def test_remove_file_active_state_has_diff_file_and_file_elsewhere(self):
2612
state = self.assertUpdate(
2613
active=[('file', 'file-id-2'),
2614
('other-file', 'file-id')],
2615
basis =[('file', 'file-id')],
2619
def test_add_file_matching_active_state(self):
2620
state = self.assertUpdate(
2621
active=[('file', 'file-id')],
2623
target=[('file', 'file-id')],
2626
def test_add_file_in_empty_dir_not_matching_active_state(self):
2627
state = self.assertUpdate(
2629
basis=[('dir/', 'dir-id')],
2630
target=[('dir/', 'dir-id', 'basis'), ('dir/file', 'file-id')],
2633
def test_add_file_missing_in_active_state(self):
2634
state = self.assertUpdate(
2637
target=[('file', 'file-id')],
2640
def test_add_file_elsewhere_in_active_state(self):
2641
state = self.assertUpdate(
2642
active=[('other-file', 'file-id')],
2644
target=[('file', 'file-id')],
2647
def test_add_file_active_state_has_diff_file_and_file_elsewhere(self):
2648
state = self.assertUpdate(
2649
active=[('other-file', 'file-id'),
2650
('file', 'file-id-2')],
2652
target=[('file', 'file-id')],
2655
def test_rename_file_matching_active_state(self):
2656
state = self.assertUpdate(
2657
active=[('other-file', 'file-id')],
2658
basis =[('file', 'file-id')],
2659
target=[('other-file', 'file-id')],
2662
def test_rename_file_missing_in_active_state(self):
2663
state = self.assertUpdate(
2665
basis =[('file', 'file-id')],
2666
target=[('other-file', 'file-id')],
2669
def test_rename_file_present_elsewhere_in_active_state(self):
2670
state = self.assertUpdate(
2671
active=[('third', 'file-id')],
2672
basis =[('file', 'file-id')],
2673
target=[('other-file', 'file-id')],
2676
def test_rename_file_active_state_has_diff_source_file(self):
2677
state = self.assertUpdate(
2678
active=[('file', 'file-id-2')],
2679
basis =[('file', 'file-id')],
2680
target=[('other-file', 'file-id')],
2683
def test_rename_file_active_state_has_diff_target_file(self):
2684
state = self.assertUpdate(
2685
active=[('other-file', 'file-id-2')],
2686
basis =[('file', 'file-id')],
2687
target=[('other-file', 'file-id')],
2690
def test_rename_file_active_has_swapped_files(self):
2691
state = self.assertUpdate(
2692
active=[('file', 'file-id'),
2693
('other-file', 'file-id-2')],
2694
basis= [('file', 'file-id'),
2695
('other-file', 'file-id-2')],
2696
target=[('file', 'file-id-2'),
2697
('other-file', 'file-id')])
2699
def test_rename_file_basis_has_swapped_files(self):
2700
state = self.assertUpdate(
2701
active=[('file', 'file-id'),
2702
('other-file', 'file-id-2')],
2703
basis= [('file', 'file-id-2'),
2704
('other-file', 'file-id')],
2705
target=[('file', 'file-id'),
2706
('other-file', 'file-id-2')])
2708
def test_rename_directory_with_contents(self):
2709
state = self.assertUpdate( # active matches basis
2710
active=[('dir1/', 'dir-id'),
2711
('dir1/file', 'file-id')],
2712
basis= [('dir1/', 'dir-id'),
2713
('dir1/file', 'file-id')],
2714
target=[('dir2/', 'dir-id'),
2715
('dir2/file', 'file-id')])
2716
state = self.assertUpdate( # active matches target
2717
active=[('dir2/', 'dir-id'),
2718
('dir2/file', 'file-id')],
2719
basis= [('dir1/', 'dir-id'),
2720
('dir1/file', 'file-id')],
2721
target=[('dir2/', 'dir-id'),
2722
('dir2/file', 'file-id')])
2723
state = self.assertUpdate( # active empty
2725
basis= [('dir1/', 'dir-id'),
2726
('dir1/file', 'file-id')],
2727
target=[('dir2/', 'dir-id'),
2728
('dir2/file', 'file-id')])
2729
state = self.assertUpdate( # active present at other location
2730
active=[('dir3/', 'dir-id'),
2731
('dir3/file', 'file-id')],
2732
basis= [('dir1/', 'dir-id'),
2733
('dir1/file', 'file-id')],
2734
target=[('dir2/', 'dir-id'),
2735
('dir2/file', 'file-id')])
2736
state = self.assertUpdate( # active has different ids
2737
active=[('dir1/', 'dir1-id'),
2738
('dir1/file', 'file1-id'),
2739
('dir2/', 'dir2-id'),
2740
('dir2/file', 'file2-id')],
2741
basis= [('dir1/', 'dir-id'),
2742
('dir1/file', 'file-id')],
2743
target=[('dir2/', 'dir-id'),
2744
('dir2/file', 'file-id')])
2746
def test_invalid_file_not_present(self):
2747
state = self.assertBadDelta(
2748
active=[('file', 'file-id')],
2749
basis= [('file', 'file-id')],
2750
delta=[('other-file', 'file', 'file-id')])
2752
def test_invalid_new_id_same_path(self):
2753
# The bad entry comes after
2754
state = self.assertBadDelta(
2755
active=[('file', 'file-id')],
2756
basis= [('file', 'file-id')],
2757
delta=[(None, 'file', 'file-id-2')])
2758
# The bad entry comes first
2759
state = self.assertBadDelta(
2760
active=[('file', 'file-id-2')],
2761
basis=[('file', 'file-id-2')],
2762
delta=[(None, 'file', 'file-id')])
2764
def test_invalid_existing_id(self):
2765
state = self.assertBadDelta(
2766
active=[('file', 'file-id')],
2767
basis= [('file', 'file-id')],
2768
delta=[(None, 'file', 'file-id')])
2770
def test_invalid_parent_missing(self):
2771
state = self.assertBadDelta(
2774
delta=[(None, 'path/path2', 'file-id')])
2775
# Note: we force the active tree to have the directory, by knowing how
2776
# path_to_ie handles entries with missing parents
2777
state = self.assertBadDelta(
2778
active=[('path/', 'path-id')],
2780
delta=[(None, 'path/path2', 'file-id')])
2781
state = self.assertBadDelta(
2782
active=[('path/', 'path-id'),
2783
('path/path2', 'file-id')],
2785
delta=[(None, 'path/path2', 'file-id')])
2787
def test_renamed_dir_same_path(self):
2788
# We replace the parent directory, with another parent dir. But the C
2789
# file doesn't look like it has been moved.
2790
state = self.assertUpdate(# Same as basis
2791
active=[('dir/', 'A-id'),
2793
basis= [('dir/', 'A-id'),
2795
target=[('dir/', 'C-id'),
2797
state = self.assertUpdate(# Same as target
2798
active=[('dir/', 'C-id'),
2800
basis= [('dir/', 'A-id'),
2802
target=[('dir/', 'C-id'),
2804
state = self.assertUpdate(# empty active
2806
basis= [('dir/', 'A-id'),
2808
target=[('dir/', 'C-id'),
2810
state = self.assertUpdate(# different active
2811
active=[('dir/', 'D-id'),
2813
basis= [('dir/', 'A-id'),
2815
target=[('dir/', 'C-id'),
2818
def test_parent_child_swap(self):
2819
state = self.assertUpdate(# Same as basis
2820
active=[('A/', 'A-id'),
2823
basis= [('A/', 'A-id'),
2826
target=[('A/', 'B-id'),
2829
state = self.assertUpdate(# Same as target
2830
active=[('A/', 'B-id'),
2833
basis= [('A/', 'A-id'),
2836
target=[('A/', 'B-id'),
2839
state = self.assertUpdate(# empty active
2841
basis= [('A/', 'A-id'),
2844
target=[('A/', 'B-id'),
2847
state = self.assertUpdate(# different active
2848
active=[('D/', 'A-id'),
2851
basis= [('A/', 'A-id'),
2854
target=[('A/', 'B-id'),
2858
def test_change_root_id(self):
2859
state = self.assertUpdate( # same as basis
2860
active=[('', 'root-id'),
2861
('file', 'file-id')],
2862
basis= [('', 'root-id'),
2863
('file', 'file-id')],
2864
target=[('', 'target-root-id'),
2865
('file', 'file-id')])
2866
state = self.assertUpdate( # same as target
2867
active=[('', 'target-root-id'),
2868
('file', 'file-id')],
2869
basis= [('', 'root-id'),
2870
('file', 'file-id')],
2871
target=[('', 'target-root-id'),
2872
('file', 'root-id')])
2873
state = self.assertUpdate( # all different
2874
active=[('', 'active-root-id'),
2875
('file', 'file-id')],
2876
basis= [('', 'root-id'),
2877
('file', 'file-id')],
2878
target=[('', 'target-root-id'),
2879
('file', 'root-id')])
2881
def test_change_file_absent_in_active(self):
2882
state = self.assertUpdate(
2884
basis= [('file', 'file-id')],
2885
target=[('file', 'file-id')])
2887
def test_invalid_changed_file(self):
2888
state = self.assertBadDelta( # Not present in basis
2889
active=[('file', 'file-id')],
2891
delta=[('file', 'file', 'file-id')])
2892
state = self.assertBadDelta( # present at another location in basis
2893
active=[('file', 'file-id')],
2894
basis= [('other-file', 'file-id')],
2895
delta=[('file', 'file', 'file-id')])