2336
2438
self.assertTrue(len(statvalue) >= 10)
2337
2439
self.assertEqual(len(text), statvalue.st_size)
2338
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.inventory,
2531
[('basis', basis_tree)], [])
2532
delta = target_tree.inventory._make_delta(basis_tree.inventory)
2533
state.update_basis_by_delta(delta, 'target')
2535
dirstate_tree = workingtree_4.DirStateRevisionTree(state,
2537
# The target now that delta has been applied should match the
2539
self.assertEqual([], list(dirstate_tree.iter_changes(target_tree)))
2540
# And the dirblock state should be identical to the state if we created
2542
state2 = self.create_empty_dirstate()
2543
state2.set_state_from_scratch(active_tree.inventory,
2544
[('target', target_tree)], [])
2545
self.assertEqual(state2._dirblocks, state._dirblocks)
2548
def assertBadDelta(self, active, basis, delta):
2549
"""Test that we raise InconsistentDelta when appropriate.
2551
:param active: The active tree shape
2552
:param basis: The basis tree shape
2553
:param delta: A description of the delta to apply. Similar to the form
2554
for regular inventory deltas, but omitting the InventoryEntry.
2555
So adding a file is: (None, 'path', 'file-id')
2556
Adding a directory is: (None, 'path/', 'dir-id')
2557
Renaming a dir is: ('old/', 'new/', 'dir-id')
2560
active_tree = self.create_tree_from_shape('active', active)
2561
basis_tree = self.create_tree_from_shape('basis', basis)
2562
inv_delta = self.create_inv_delta(delta, 'target')
2563
state = self.create_empty_dirstate()
2564
state.set_state_from_scratch(active_tree.inventory,
2565
[('basis', basis_tree)], [])
2566
self.assertRaises(errors.InconsistentDelta,
2567
state.update_basis_by_delta, inv_delta, 'target')
2569
## state.update_basis_by_delta(inv_delta, 'target')
2570
## except errors.InconsistentDelta, e:
2571
## import pdb; pdb.set_trace()
2573
## import pdb; pdb.set_trace()
2574
self.assertTrue(state._changes_aborted)
2576
def test_remove_file_matching_active_state(self):
2577
state = self.assertUpdate(
2579
basis =[('file', 'file-id')],
2583
def test_remove_file_present_in_active_state(self):
2584
state = self.assertUpdate(
2585
active=[('file', 'file-id')],
2586
basis =[('file', 'file-id')],
2590
def test_remove_file_present_elsewhere_in_active_state(self):
2591
state = self.assertUpdate(
2592
active=[('other-file', 'file-id')],
2593
basis =[('file', 'file-id')],
2597
def test_remove_file_active_state_has_diff_file(self):
2598
state = self.assertUpdate(
2599
active=[('file', 'file-id-2')],
2600
basis =[('file', 'file-id')],
2604
def test_remove_file_active_state_has_diff_file_and_file_elsewhere(self):
2605
state = self.assertUpdate(
2606
active=[('file', 'file-id-2'),
2607
('other-file', 'file-id')],
2608
basis =[('file', 'file-id')],
2612
def test_add_file_matching_active_state(self):
2613
state = self.assertUpdate(
2614
active=[('file', 'file-id')],
2616
target=[('file', 'file-id')],
2619
def test_add_file_missing_in_active_state(self):
2620
state = self.assertUpdate(
2623
target=[('file', 'file-id')],
2626
def test_add_file_elsewhere_in_active_state(self):
2627
state = self.assertUpdate(
2628
active=[('other-file', 'file-id')],
2630
target=[('file', 'file-id')],
2633
def test_add_file_active_state_has_diff_file_and_file_elsewhere(self):
2634
state = self.assertUpdate(
2635
active=[('other-file', 'file-id'),
2636
('file', 'file-id-2')],
2638
target=[('file', 'file-id')],
2641
def test_rename_file_matching_active_state(self):
2642
state = self.assertUpdate(
2643
active=[('other-file', 'file-id')],
2644
basis =[('file', 'file-id')],
2645
target=[('other-file', 'file-id')],
2648
def test_rename_file_missing_in_active_state(self):
2649
state = self.assertUpdate(
2651
basis =[('file', 'file-id')],
2652
target=[('other-file', 'file-id')],
2655
def test_rename_file_present_elsewhere_in_active_state(self):
2656
state = self.assertUpdate(
2657
active=[('third', 'file-id')],
2658
basis =[('file', 'file-id')],
2659
target=[('other-file', 'file-id')],
2662
def test_rename_file_active_state_has_diff_source_file(self):
2663
state = self.assertUpdate(
2664
active=[('file', 'file-id-2')],
2665
basis =[('file', 'file-id')],
2666
target=[('other-file', 'file-id')],
2669
def test_rename_file_active_state_has_diff_target_file(self):
2670
state = self.assertUpdate(
2671
active=[('other-file', 'file-id-2')],
2672
basis =[('file', 'file-id')],
2673
target=[('other-file', 'file-id')],
2676
def test_rename_file_active_has_swapped_files(self):
2677
state = self.assertUpdate(
2678
active=[('file', 'file-id'),
2679
('other-file', 'file-id-2')],
2680
basis= [('file', 'file-id'),
2681
('other-file', 'file-id-2')],
2682
target=[('file', 'file-id-2'),
2683
('other-file', 'file-id')])
2685
def test_rename_file_basis_has_swapped_files(self):
2686
state = self.assertUpdate(
2687
active=[('file', 'file-id'),
2688
('other-file', 'file-id-2')],
2689
basis= [('file', 'file-id-2'),
2690
('other-file', 'file-id')],
2691
target=[('file', 'file-id'),
2692
('other-file', 'file-id-2')])
2694
def test_rename_directory_with_contents(self):
2695
state = self.assertUpdate( # active matches basis
2696
active=[('dir1/', 'dir-id'),
2697
('dir1/file', 'file-id')],
2698
basis= [('dir1/', 'dir-id'),
2699
('dir1/file', 'file-id')],
2700
target=[('dir2/', 'dir-id'),
2701
('dir2/file', 'file-id')])
2702
state = self.assertUpdate( # active matches target
2703
active=[('dir2/', 'dir-id'),
2704
('dir2/file', 'file-id')],
2705
basis= [('dir1/', 'dir-id'),
2706
('dir1/file', 'file-id')],
2707
target=[('dir2/', 'dir-id'),
2708
('dir2/file', 'file-id')])
2709
state = self.assertUpdate( # active empty
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 present at other location
2716
active=[('dir3/', 'dir-id'),
2717
('dir3/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 has different ids
2723
active=[('dir1/', 'dir1-id'),
2724
('dir1/file', 'file1-id'),
2725
('dir2/', 'dir2-id'),
2726
('dir2/file', 'file2-id')],
2727
basis= [('dir1/', 'dir-id'),
2728
('dir1/file', 'file-id')],
2729
target=[('dir2/', 'dir-id'),
2730
('dir2/file', 'file-id')])
2732
def test_invalid_file_not_present(self):
2733
state = self.assertBadDelta(
2734
active=[('file', 'file-id')],
2735
basis= [('file', 'file-id')],
2736
delta=[('other-file', 'file', 'file-id')])
2738
def test_invalid_new_id_same_path(self):
2739
# The bad entry comes after
2740
state = self.assertBadDelta(
2741
active=[('file', 'file-id')],
2742
basis= [('file', 'file-id')],
2743
delta=[(None, 'file', 'file-id-2')])
2744
# The bad entry comes first
2745
state = self.assertBadDelta(
2746
active=[('file', 'file-id-2')],
2747
basis=[('file', 'file-id-2')],
2748
delta=[(None, 'file', 'file-id')])
2750
def test_invalid_existing_id(self):
2751
state = self.assertBadDelta(
2752
active=[('file', 'file-id')],
2753
basis= [('file', 'file-id')],
2754
delta=[(None, 'file', 'file-id')])
2756
def test_invalid_parent_missing(self):
2757
state = self.assertBadDelta(
2760
delta=[(None, 'path/path2', 'file-id')])
2761
# Note: we force the active tree to have the directory, by knowing how
2762
# path_to_ie handles entries with missing parents
2763
state = self.assertBadDelta(
2764
active=[('path/', 'path-id')],
2766
delta=[(None, 'path/path2', 'file-id')])
2767
state = self.assertBadDelta(
2768
active=[('path/', 'path-id'),
2769
('path/path2', 'file-id')],
2771
delta=[(None, 'path/path2', 'file-id')])
2773
def test_renamed_dir_same_path(self):
2774
# We replace the parent directory, with another parent dir. But the C
2775
# file doesn't look like it has been moved.
2776
state = self.assertUpdate(# Same as basis
2777
active=[('dir/', 'A-id'),
2779
basis= [('dir/', 'A-id'),
2781
target=[('dir/', 'C-id'),
2783
state = self.assertUpdate(# Same as target
2784
active=[('dir/', 'C-id'),
2786
basis= [('dir/', 'A-id'),
2788
target=[('dir/', 'C-id'),
2790
state = self.assertUpdate(# empty active
2792
basis= [('dir/', 'A-id'),
2794
target=[('dir/', 'C-id'),
2796
state = self.assertUpdate(# different active
2797
active=[('dir/', 'D-id'),
2799
basis= [('dir/', 'A-id'),
2801
target=[('dir/', 'C-id'),
2804
def test_parent_child_swap(self):
2805
state = self.assertUpdate(# Same as basis
2806
active=[('A/', 'A-id'),
2809
basis= [('A/', 'A-id'),
2812
target=[('A/', 'B-id'),
2815
state = self.assertUpdate(# Same as target
2816
active=[('A/', 'B-id'),
2819
basis= [('A/', 'A-id'),
2822
target=[('A/', 'B-id'),
2825
state = self.assertUpdate(# empty active
2827
basis= [('A/', 'A-id'),
2830
target=[('A/', 'B-id'),
2833
state = self.assertUpdate(# different active
2834
active=[('D/', 'A-id'),
2837
basis= [('A/', 'A-id'),
2840
target=[('A/', 'B-id'),
2844
def test_change_root_id(self):
2845
state = self.assertUpdate( # same as basis
2846
active=[('', 'root-id'),
2847
('file', 'file-id')],
2848
basis= [('', 'root-id'),
2849
('file', 'file-id')],
2850
target=[('', 'target-root-id'),
2851
('file', 'file-id')])
2852
state = self.assertUpdate( # same as target
2853
active=[('', 'target-root-id'),
2854
('file', 'file-id')],
2855
basis= [('', 'root-id'),
2856
('file', 'file-id')],
2857
target=[('', 'target-root-id'),
2858
('file', 'root-id')])
2859
state = self.assertUpdate( # all different
2860
active=[('', 'active-root-id'),
2861
('file', 'file-id')],
2862
basis= [('', 'root-id'),
2863
('file', 'file-id')],
2864
target=[('', 'target-root-id'),
2865
('file', 'root-id')])
2867
def test_change_file_absent_in_active(self):
2868
state = self.assertUpdate(
2870
basis= [('file', 'file-id')],
2871
target=[('file', 'file-id')])
2873
def test_invalid_changed_file(self):
2874
state = self.assertBadDelta( # Not present in basis
2875
active=[('file', 'file-id')],
2877
delta=[('file', 'file', 'file-id')])
2878
state = self.assertBadDelta( # present at another location in basis
2879
active=[('file', 'file-id')],
2880
basis= [('other-file', 'file-id')],
2881
delta=[('file', 'file', 'file-id')])