2377
2438
self.assertTrue(len(statvalue) >= 10)
2378
2439
self.assertEqual(len(text), statvalue.st_size)
2379
2440
self.assertEqual(expected_sha, sha1)
2443
class _Repo(object):
2444
"""A minimal api to get InventoryRevisionTree to work."""
2447
default_format = bzrdir.format_registry.make_bzrdir('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)
2483
for path, file_id in shape:
2485
# Replace the root entry
2486
del inv._byid[inv.root.file_id]
2487
inv.root.file_id = file_id
2488
inv._byid[file_id] = inv.root
2489
dir_ids[''] = file_id
2491
inv.add(self.path_to_ie(path, file_id, rev_id, dir_ids))
2492
return revisiontree.InventoryRevisionTree(_Repo(), inv, rev_id)
2494
def create_empty_dirstate(self):
2495
fd, path = tempfile.mkstemp(prefix='bzr-dirstate')
2496
self.addCleanup(os.remove, path)
2498
state = dirstate.DirState.initialize(path)
2499
self.addCleanup(state.unlock)
2502
def create_inv_delta(self, delta, rev_id):
2503
"""Translate a 'delta shape' into an actual InventoryDelta"""
2504
dir_ids = {'': 'root-id'}
2506
for old_path, new_path, file_id in delta:
2507
if old_path is not None and old_path.endswith('/'):
2508
# Don't have to actually do anything for this, because only
2509
# new_path creates InventoryEntries
2510
old_path = old_path[:-1]
2511
if new_path is None: # Delete
2512
inv_delta.append((old_path, None, file_id, None))
2514
ie = self.path_to_ie(new_path, file_id, rev_id, dir_ids)
2515
inv_delta.append((old_path, new_path, file_id, ie))
2518
def assertUpdate(self, active, basis, target):
2519
"""Assert that update_basis_by_delta works how we want.
2521
Set up a DirState object with active_shape for tree 0, basis_shape for
2522
tree 1. Then apply the delta from basis_shape to target_shape,
2523
and assert that the DirState is still valid, and that its stored
2524
content matches the target_shape.
2526
active_tree = self.create_tree_from_shape('active', active)
2527
basis_tree = self.create_tree_from_shape('basis', basis)
2528
target_tree = self.create_tree_from_shape('target', target)
2529
state = self.create_empty_dirstate()
2530
state.set_state_from_scratch(active_tree.root_inventory,
2531
[('basis', basis_tree)], [])
2532
delta = target_tree.root_inventory._make_delta(
2533
basis_tree.root_inventory)
2534
state.update_basis_by_delta(delta, 'target')
2536
dirstate_tree = workingtree_4.DirStateRevisionTree(state,
2538
# The target now that delta has been applied should match the
2540
self.assertEqual([], list(dirstate_tree.iter_changes(target_tree)))
2541
# And the dirblock state should be identical to the state if we created
2543
state2 = self.create_empty_dirstate()
2544
state2.set_state_from_scratch(active_tree.root_inventory,
2545
[('target', target_tree)], [])
2546
self.assertEqual(state2._dirblocks, state._dirblocks)
2549
def assertBadDelta(self, active, basis, delta):
2550
"""Test that we raise InconsistentDelta when appropriate.
2552
:param active: The active tree shape
2553
:param basis: The basis tree shape
2554
:param delta: A description of the delta to apply. Similar to the form
2555
for regular inventory deltas, but omitting the InventoryEntry.
2556
So adding a file is: (None, 'path', 'file-id')
2557
Adding a directory is: (None, 'path/', 'dir-id')
2558
Renaming a dir is: ('old/', 'new/', 'dir-id')
2561
active_tree = self.create_tree_from_shape('active', active)
2562
basis_tree = self.create_tree_from_shape('basis', basis)
2563
inv_delta = self.create_inv_delta(delta, 'target')
2564
state = self.create_empty_dirstate()
2565
state.set_state_from_scratch(active_tree.root_inventory,
2566
[('basis', basis_tree)], [])
2567
self.assertRaises(errors.InconsistentDelta,
2568
state.update_basis_by_delta, inv_delta, 'target')
2570
## state.update_basis_by_delta(inv_delta, 'target')
2571
## except errors.InconsistentDelta, e:
2572
## import pdb; pdb.set_trace()
2574
## import pdb; pdb.set_trace()
2575
self.assertTrue(state._changes_aborted)
2577
def test_remove_file_matching_active_state(self):
2578
state = self.assertUpdate(
2580
basis =[('file', 'file-id')],
2584
def test_remove_file_present_in_active_state(self):
2585
state = self.assertUpdate(
2586
active=[('file', 'file-id')],
2587
basis =[('file', 'file-id')],
2591
def test_remove_file_present_elsewhere_in_active_state(self):
2592
state = self.assertUpdate(
2593
active=[('other-file', 'file-id')],
2594
basis =[('file', 'file-id')],
2598
def test_remove_file_active_state_has_diff_file(self):
2599
state = self.assertUpdate(
2600
active=[('file', 'file-id-2')],
2601
basis =[('file', 'file-id')],
2605
def test_remove_file_active_state_has_diff_file_and_file_elsewhere(self):
2606
state = self.assertUpdate(
2607
active=[('file', 'file-id-2'),
2608
('other-file', 'file-id')],
2609
basis =[('file', 'file-id')],
2613
def test_add_file_matching_active_state(self):
2614
state = self.assertUpdate(
2615
active=[('file', 'file-id')],
2617
target=[('file', 'file-id')],
2620
def test_add_file_missing_in_active_state(self):
2621
state = self.assertUpdate(
2624
target=[('file', 'file-id')],
2627
def test_add_file_elsewhere_in_active_state(self):
2628
state = self.assertUpdate(
2629
active=[('other-file', 'file-id')],
2631
target=[('file', 'file-id')],
2634
def test_add_file_active_state_has_diff_file_and_file_elsewhere(self):
2635
state = self.assertUpdate(
2636
active=[('other-file', 'file-id'),
2637
('file', 'file-id-2')],
2639
target=[('file', 'file-id')],
2642
def test_rename_file_matching_active_state(self):
2643
state = self.assertUpdate(
2644
active=[('other-file', 'file-id')],
2645
basis =[('file', 'file-id')],
2646
target=[('other-file', 'file-id')],
2649
def test_rename_file_missing_in_active_state(self):
2650
state = self.assertUpdate(
2652
basis =[('file', 'file-id')],
2653
target=[('other-file', 'file-id')],
2656
def test_rename_file_present_elsewhere_in_active_state(self):
2657
state = self.assertUpdate(
2658
active=[('third', 'file-id')],
2659
basis =[('file', 'file-id')],
2660
target=[('other-file', 'file-id')],
2663
def test_rename_file_active_state_has_diff_source_file(self):
2664
state = self.assertUpdate(
2665
active=[('file', 'file-id-2')],
2666
basis =[('file', 'file-id')],
2667
target=[('other-file', 'file-id')],
2670
def test_rename_file_active_state_has_diff_target_file(self):
2671
state = self.assertUpdate(
2672
active=[('other-file', 'file-id-2')],
2673
basis =[('file', 'file-id')],
2674
target=[('other-file', 'file-id')],
2677
def test_rename_file_active_has_swapped_files(self):
2678
state = self.assertUpdate(
2679
active=[('file', 'file-id'),
2680
('other-file', 'file-id-2')],
2681
basis= [('file', 'file-id'),
2682
('other-file', 'file-id-2')],
2683
target=[('file', 'file-id-2'),
2684
('other-file', 'file-id')])
2686
def test_rename_file_basis_has_swapped_files(self):
2687
state = self.assertUpdate(
2688
active=[('file', 'file-id'),
2689
('other-file', 'file-id-2')],
2690
basis= [('file', 'file-id-2'),
2691
('other-file', 'file-id')],
2692
target=[('file', 'file-id'),
2693
('other-file', 'file-id-2')])
2695
def test_rename_directory_with_contents(self):
2696
state = self.assertUpdate( # active matches basis
2697
active=[('dir1/', 'dir-id'),
2698
('dir1/file', 'file-id')],
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 matches target
2704
active=[('dir2/', 'dir-id'),
2705
('dir2/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 empty
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 present at other location
2717
active=[('dir3/', 'dir-id'),
2718
('dir3/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 has different ids
2724
active=[('dir1/', 'dir1-id'),
2725
('dir1/file', 'file1-id'),
2726
('dir2/', 'dir2-id'),
2727
('dir2/file', 'file2-id')],
2728
basis= [('dir1/', 'dir-id'),
2729
('dir1/file', 'file-id')],
2730
target=[('dir2/', 'dir-id'),
2731
('dir2/file', 'file-id')])
2733
def test_invalid_file_not_present(self):
2734
state = self.assertBadDelta(
2735
active=[('file', 'file-id')],
2736
basis= [('file', 'file-id')],
2737
delta=[('other-file', 'file', 'file-id')])
2739
def test_invalid_new_id_same_path(self):
2740
# The bad entry comes after
2741
state = self.assertBadDelta(
2742
active=[('file', 'file-id')],
2743
basis= [('file', 'file-id')],
2744
delta=[(None, 'file', 'file-id-2')])
2745
# The bad entry comes first
2746
state = self.assertBadDelta(
2747
active=[('file', 'file-id-2')],
2748
basis=[('file', 'file-id-2')],
2749
delta=[(None, 'file', 'file-id')])
2751
def test_invalid_existing_id(self):
2752
state = self.assertBadDelta(
2753
active=[('file', 'file-id')],
2754
basis= [('file', 'file-id')],
2755
delta=[(None, 'file', 'file-id')])
2757
def test_invalid_parent_missing(self):
2758
state = self.assertBadDelta(
2761
delta=[(None, 'path/path2', 'file-id')])
2762
# Note: we force the active tree to have the directory, by knowing how
2763
# path_to_ie handles entries with missing parents
2764
state = self.assertBadDelta(
2765
active=[('path/', 'path-id')],
2767
delta=[(None, 'path/path2', 'file-id')])
2768
state = self.assertBadDelta(
2769
active=[('path/', 'path-id'),
2770
('path/path2', 'file-id')],
2772
delta=[(None, 'path/path2', 'file-id')])
2774
def test_renamed_dir_same_path(self):
2775
# We replace the parent directory, with another parent dir. But the C
2776
# file doesn't look like it has been moved.
2777
state = self.assertUpdate(# Same as basis
2778
active=[('dir/', 'A-id'),
2780
basis= [('dir/', 'A-id'),
2782
target=[('dir/', 'C-id'),
2784
state = self.assertUpdate(# Same as target
2785
active=[('dir/', 'C-id'),
2787
basis= [('dir/', 'A-id'),
2789
target=[('dir/', 'C-id'),
2791
state = self.assertUpdate(# empty active
2793
basis= [('dir/', 'A-id'),
2795
target=[('dir/', 'C-id'),
2797
state = self.assertUpdate(# different active
2798
active=[('dir/', 'D-id'),
2800
basis= [('dir/', 'A-id'),
2802
target=[('dir/', 'C-id'),
2805
def test_parent_child_swap(self):
2806
state = self.assertUpdate(# Same as basis
2807
active=[('A/', 'A-id'),
2810
basis= [('A/', 'A-id'),
2813
target=[('A/', 'B-id'),
2816
state = self.assertUpdate(# Same as target
2817
active=[('A/', 'B-id'),
2820
basis= [('A/', 'A-id'),
2823
target=[('A/', 'B-id'),
2826
state = self.assertUpdate(# empty active
2828
basis= [('A/', 'A-id'),
2831
target=[('A/', 'B-id'),
2834
state = self.assertUpdate(# different active
2835
active=[('D/', 'A-id'),
2838
basis= [('A/', 'A-id'),
2841
target=[('A/', 'B-id'),
2845
def test_change_root_id(self):
2846
state = self.assertUpdate( # same as basis
2847
active=[('', 'root-id'),
2848
('file', 'file-id')],
2849
basis= [('', 'root-id'),
2850
('file', 'file-id')],
2851
target=[('', 'target-root-id'),
2852
('file', 'file-id')])
2853
state = self.assertUpdate( # same as target
2854
active=[('', 'target-root-id'),
2855
('file', 'file-id')],
2856
basis= [('', 'root-id'),
2857
('file', 'file-id')],
2858
target=[('', 'target-root-id'),
2859
('file', 'root-id')])
2860
state = self.assertUpdate( # all different
2861
active=[('', 'active-root-id'),
2862
('file', 'file-id')],
2863
basis= [('', 'root-id'),
2864
('file', 'file-id')],
2865
target=[('', 'target-root-id'),
2866
('file', 'root-id')])
2868
def test_change_file_absent_in_active(self):
2869
state = self.assertUpdate(
2871
basis= [('file', 'file-id')],
2872
target=[('file', 'file-id')])
2874
def test_invalid_changed_file(self):
2875
state = self.assertBadDelta( # Not present in basis
2876
active=[('file', 'file-id')],
2878
delta=[('file', 'file', 'file-id')])
2879
state = self.assertBadDelta( # present at another location in basis
2880
active=[('file', 'file-id')],
2881
basis= [('other-file', 'file-id')],
2882
delta=[('file', 'file', 'file-id')])