2320
2438
self.assertTrue(len(statvalue) >= 10)
2321
2439
self.assertEqual(len(text), statvalue.st_size)
2322
2440
self.assertEqual(expected_sha, sha1)
2443
class _Repo(object):
2444
"""A minimal api to get InventoryRevisionTree to work."""
2447
default_format = controldir.format_registry.make_controldir('default')
2448
self._format = default_format.repository_format
2450
def lock_read(self):
2457
class TestUpdateBasisByDelta(tests.TestCase):
2459
def path_to_ie(self, path, file_id, rev_id, dir_ids):
2460
if path.endswith('/'):
2465
dirname, basename = osutils.split(path)
2467
dir_id = dir_ids[dirname]
2469
dir_id = osutils.basename(dirname) + '-id'
2471
ie = inventory.InventoryDirectory(file_id, basename, dir_id)
2472
dir_ids[path] = file_id
2474
ie = inventory.InventoryFile(file_id, basename, dir_id)
2477
ie.revision = rev_id
2480
def create_tree_from_shape(self, rev_id, shape):
2481
dir_ids = {'': 'root-id'}
2482
inv = inventory.Inventory('root-id', rev_id)
2485
path, file_id = info
2488
path, file_id, ie_rev_id = info
2490
# Replace the root entry
2491
del inv._byid[inv.root.file_id]
2492
inv.root.file_id = file_id
2493
inv._byid[file_id] = inv.root
2494
dir_ids[''] = file_id
2496
inv.add(self.path_to_ie(path, file_id, ie_rev_id, dir_ids))
2497
return revisiontree.InventoryRevisionTree(_Repo(), inv, rev_id)
2499
def create_empty_dirstate(self):
2500
fd, path = tempfile.mkstemp(prefix='bzr-dirstate')
2501
self.addCleanup(os.remove, path)
2503
state = dirstate.DirState.initialize(path)
2504
self.addCleanup(state.unlock)
2507
def create_inv_delta(self, delta, rev_id):
2508
"""Translate a 'delta shape' into an actual InventoryDelta"""
2509
dir_ids = {'': 'root-id'}
2511
for old_path, new_path, file_id in delta:
2512
if old_path is not None and old_path.endswith('/'):
2513
# Don't have to actually do anything for this, because only
2514
# new_path creates InventoryEntries
2515
old_path = old_path[:-1]
2516
if new_path is None: # Delete
2517
inv_delta.append((old_path, None, file_id, None))
2519
ie = self.path_to_ie(new_path, file_id, rev_id, dir_ids)
2520
inv_delta.append((old_path, new_path, file_id, ie))
2523
def assertUpdate(self, active, basis, target):
2524
"""Assert that update_basis_by_delta works how we want.
2526
Set up a DirState object with active_shape for tree 0, basis_shape for
2527
tree 1. Then apply the delta from basis_shape to target_shape,
2528
and assert that the DirState is still valid, and that its stored
2529
content matches the target_shape.
2531
active_tree = self.create_tree_from_shape('active', active)
2532
basis_tree = self.create_tree_from_shape('basis', basis)
2533
target_tree = self.create_tree_from_shape('target', target)
2534
state = self.create_empty_dirstate()
2535
state.set_state_from_scratch(active_tree.root_inventory,
2536
[('basis', basis_tree)], [])
2537
delta = target_tree.root_inventory._make_delta(
2538
basis_tree.root_inventory)
2539
state.update_basis_by_delta(delta, 'target')
2541
dirstate_tree = workingtree_4.DirStateRevisionTree(state,
2543
# The target now that delta has been applied should match the
2545
self.assertEqual([], list(dirstate_tree.iter_changes(target_tree)))
2546
# And the dirblock state should be identical to the state if we created
2548
state2 = self.create_empty_dirstate()
2549
state2.set_state_from_scratch(active_tree.root_inventory,
2550
[('target', target_tree)], [])
2551
self.assertEqual(state2._dirblocks, state._dirblocks)
2554
def assertBadDelta(self, active, basis, delta):
2555
"""Test that we raise InconsistentDelta when appropriate.
2557
:param active: The active tree shape
2558
:param basis: The basis tree shape
2559
:param delta: A description of the delta to apply. Similar to the form
2560
for regular inventory deltas, but omitting the InventoryEntry.
2561
So adding a file is: (None, 'path', 'file-id')
2562
Adding a directory is: (None, 'path/', 'dir-id')
2563
Renaming a dir is: ('old/', 'new/', 'dir-id')
2566
active_tree = self.create_tree_from_shape('active', active)
2567
basis_tree = self.create_tree_from_shape('basis', basis)
2568
inv_delta = self.create_inv_delta(delta, 'target')
2569
state = self.create_empty_dirstate()
2570
state.set_state_from_scratch(active_tree.root_inventory,
2571
[('basis', basis_tree)], [])
2572
self.assertRaises(errors.InconsistentDelta,
2573
state.update_basis_by_delta, inv_delta, 'target')
2575
## state.update_basis_by_delta(inv_delta, 'target')
2576
## except errors.InconsistentDelta, e:
2577
## import pdb; pdb.set_trace()
2579
## import pdb; pdb.set_trace()
2580
self.assertTrue(state._changes_aborted)
2582
def test_remove_file_matching_active_state(self):
2583
state = self.assertUpdate(
2585
basis =[('file', 'file-id')],
2589
def test_remove_file_present_in_active_state(self):
2590
state = self.assertUpdate(
2591
active=[('file', 'file-id')],
2592
basis =[('file', 'file-id')],
2596
def test_remove_file_present_elsewhere_in_active_state(self):
2597
state = self.assertUpdate(
2598
active=[('other-file', 'file-id')],
2599
basis =[('file', 'file-id')],
2603
def test_remove_file_active_state_has_diff_file(self):
2604
state = self.assertUpdate(
2605
active=[('file', 'file-id-2')],
2606
basis =[('file', 'file-id')],
2610
def test_remove_file_active_state_has_diff_file_and_file_elsewhere(self):
2611
state = self.assertUpdate(
2612
active=[('file', 'file-id-2'),
2613
('other-file', 'file-id')],
2614
basis =[('file', 'file-id')],
2618
def test_add_file_matching_active_state(self):
2619
state = self.assertUpdate(
2620
active=[('file', 'file-id')],
2622
target=[('file', 'file-id')],
2625
def test_add_file_in_empty_dir_not_matching_active_state(self):
2626
state = self.assertUpdate(
2628
basis=[('dir/', 'dir-id')],
2629
target=[('dir/', 'dir-id', 'basis'), ('dir/file', 'file-id')],
2632
def test_add_file_missing_in_active_state(self):
2633
state = self.assertUpdate(
2636
target=[('file', 'file-id')],
2639
def test_add_file_elsewhere_in_active_state(self):
2640
state = self.assertUpdate(
2641
active=[('other-file', 'file-id')],
2643
target=[('file', 'file-id')],
2646
def test_add_file_active_state_has_diff_file_and_file_elsewhere(self):
2647
state = self.assertUpdate(
2648
active=[('other-file', 'file-id'),
2649
('file', 'file-id-2')],
2651
target=[('file', 'file-id')],
2654
def test_rename_file_matching_active_state(self):
2655
state = self.assertUpdate(
2656
active=[('other-file', 'file-id')],
2657
basis =[('file', 'file-id')],
2658
target=[('other-file', 'file-id')],
2661
def test_rename_file_missing_in_active_state(self):
2662
state = self.assertUpdate(
2664
basis =[('file', 'file-id')],
2665
target=[('other-file', 'file-id')],
2668
def test_rename_file_present_elsewhere_in_active_state(self):
2669
state = self.assertUpdate(
2670
active=[('third', 'file-id')],
2671
basis =[('file', 'file-id')],
2672
target=[('other-file', 'file-id')],
2675
def test_rename_file_active_state_has_diff_source_file(self):
2676
state = self.assertUpdate(
2677
active=[('file', 'file-id-2')],
2678
basis =[('file', 'file-id')],
2679
target=[('other-file', 'file-id')],
2682
def test_rename_file_active_state_has_diff_target_file(self):
2683
state = self.assertUpdate(
2684
active=[('other-file', 'file-id-2')],
2685
basis =[('file', 'file-id')],
2686
target=[('other-file', 'file-id')],
2689
def test_rename_file_active_has_swapped_files(self):
2690
state = self.assertUpdate(
2691
active=[('file', 'file-id'),
2692
('other-file', 'file-id-2')],
2693
basis= [('file', 'file-id'),
2694
('other-file', 'file-id-2')],
2695
target=[('file', 'file-id-2'),
2696
('other-file', 'file-id')])
2698
def test_rename_file_basis_has_swapped_files(self):
2699
state = self.assertUpdate(
2700
active=[('file', 'file-id'),
2701
('other-file', 'file-id-2')],
2702
basis= [('file', 'file-id-2'),
2703
('other-file', 'file-id')],
2704
target=[('file', 'file-id'),
2705
('other-file', 'file-id-2')])
2707
def test_rename_directory_with_contents(self):
2708
state = self.assertUpdate( # active matches basis
2709
active=[('dir1/', 'dir-id'),
2710
('dir1/file', 'file-id')],
2711
basis= [('dir1/', 'dir-id'),
2712
('dir1/file', 'file-id')],
2713
target=[('dir2/', 'dir-id'),
2714
('dir2/file', 'file-id')])
2715
state = self.assertUpdate( # active matches target
2716
active=[('dir2/', 'dir-id'),
2717
('dir2/file', 'file-id')],
2718
basis= [('dir1/', 'dir-id'),
2719
('dir1/file', 'file-id')],
2720
target=[('dir2/', 'dir-id'),
2721
('dir2/file', 'file-id')])
2722
state = self.assertUpdate( # active empty
2724
basis= [('dir1/', 'dir-id'),
2725
('dir1/file', 'file-id')],
2726
target=[('dir2/', 'dir-id'),
2727
('dir2/file', 'file-id')])
2728
state = self.assertUpdate( # active present at other location
2729
active=[('dir3/', 'dir-id'),
2730
('dir3/file', 'file-id')],
2731
basis= [('dir1/', 'dir-id'),
2732
('dir1/file', 'file-id')],
2733
target=[('dir2/', 'dir-id'),
2734
('dir2/file', 'file-id')])
2735
state = self.assertUpdate( # active has different ids
2736
active=[('dir1/', 'dir1-id'),
2737
('dir1/file', 'file1-id'),
2738
('dir2/', 'dir2-id'),
2739
('dir2/file', 'file2-id')],
2740
basis= [('dir1/', 'dir-id'),
2741
('dir1/file', 'file-id')],
2742
target=[('dir2/', 'dir-id'),
2743
('dir2/file', 'file-id')])
2745
def test_invalid_file_not_present(self):
2746
state = self.assertBadDelta(
2747
active=[('file', 'file-id')],
2748
basis= [('file', 'file-id')],
2749
delta=[('other-file', 'file', 'file-id')])
2751
def test_invalid_new_id_same_path(self):
2752
# The bad entry comes after
2753
state = self.assertBadDelta(
2754
active=[('file', 'file-id')],
2755
basis= [('file', 'file-id')],
2756
delta=[(None, 'file', 'file-id-2')])
2757
# The bad entry comes first
2758
state = self.assertBadDelta(
2759
active=[('file', 'file-id-2')],
2760
basis=[('file', 'file-id-2')],
2761
delta=[(None, 'file', 'file-id')])
2763
def test_invalid_existing_id(self):
2764
state = self.assertBadDelta(
2765
active=[('file', 'file-id')],
2766
basis= [('file', 'file-id')],
2767
delta=[(None, 'file', 'file-id')])
2769
def test_invalid_parent_missing(self):
2770
state = self.assertBadDelta(
2773
delta=[(None, 'path/path2', 'file-id')])
2774
# Note: we force the active tree to have the directory, by knowing how
2775
# path_to_ie handles entries with missing parents
2776
state = self.assertBadDelta(
2777
active=[('path/', 'path-id')],
2779
delta=[(None, 'path/path2', 'file-id')])
2780
state = self.assertBadDelta(
2781
active=[('path/', 'path-id'),
2782
('path/path2', 'file-id')],
2784
delta=[(None, 'path/path2', 'file-id')])
2786
def test_renamed_dir_same_path(self):
2787
# We replace the parent directory, with another parent dir. But the C
2788
# file doesn't look like it has been moved.
2789
state = self.assertUpdate(# Same as basis
2790
active=[('dir/', 'A-id'),
2792
basis= [('dir/', 'A-id'),
2794
target=[('dir/', 'C-id'),
2796
state = self.assertUpdate(# Same as target
2797
active=[('dir/', 'C-id'),
2799
basis= [('dir/', 'A-id'),
2801
target=[('dir/', 'C-id'),
2803
state = self.assertUpdate(# empty active
2805
basis= [('dir/', 'A-id'),
2807
target=[('dir/', 'C-id'),
2809
state = self.assertUpdate(# different active
2810
active=[('dir/', 'D-id'),
2812
basis= [('dir/', 'A-id'),
2814
target=[('dir/', 'C-id'),
2817
def test_parent_child_swap(self):
2818
state = self.assertUpdate(# Same as basis
2819
active=[('A/', 'A-id'),
2822
basis= [('A/', 'A-id'),
2825
target=[('A/', 'B-id'),
2828
state = self.assertUpdate(# Same as target
2829
active=[('A/', 'B-id'),
2832
basis= [('A/', 'A-id'),
2835
target=[('A/', 'B-id'),
2838
state = self.assertUpdate(# empty active
2840
basis= [('A/', 'A-id'),
2843
target=[('A/', 'B-id'),
2846
state = self.assertUpdate(# different active
2847
active=[('D/', 'A-id'),
2850
basis= [('A/', 'A-id'),
2853
target=[('A/', 'B-id'),
2857
def test_change_root_id(self):
2858
state = self.assertUpdate( # same as basis
2859
active=[('', 'root-id'),
2860
('file', 'file-id')],
2861
basis= [('', 'root-id'),
2862
('file', 'file-id')],
2863
target=[('', 'target-root-id'),
2864
('file', 'file-id')])
2865
state = self.assertUpdate( # same as target
2866
active=[('', 'target-root-id'),
2867
('file', 'file-id')],
2868
basis= [('', 'root-id'),
2869
('file', 'file-id')],
2870
target=[('', 'target-root-id'),
2871
('file', 'root-id')])
2872
state = self.assertUpdate( # all different
2873
active=[('', 'active-root-id'),
2874
('file', 'file-id')],
2875
basis= [('', 'root-id'),
2876
('file', 'file-id')],
2877
target=[('', 'target-root-id'),
2878
('file', 'root-id')])
2880
def test_change_file_absent_in_active(self):
2881
state = self.assertUpdate(
2883
basis= [('file', 'file-id')],
2884
target=[('file', 'file-id')])
2886
def test_invalid_changed_file(self):
2887
state = self.assertBadDelta( # Not present in basis
2888
active=[('file', 'file-id')],
2890
delta=[('file', 'file', 'file-id')])
2891
state = self.assertBadDelta( # present at another location in basis
2892
active=[('file', 'file-id')],
2893
basis= [('other-file', 'file-id')],
2894
delta=[('file', 'file', 'file-id')])