241
255
f_len = len(f_text)
242
256
null_stat = dirstate.DirState.NULLSTAT
244
'':(('', '', 'TREE_ROOT'), [
258
'': (('', '', 'TREE_ROOT'), [
245
259
('d', '', 0, False, null_stat),
246
260
('d', '', 0, False, revision_id),
248
'a':(('', 'a', 'a-id'), [
262
'a': (('', 'a', 'a-id'), [
249
263
('f', '', 0, False, null_stat),
250
264
('f', a_sha, a_len, False, revision_id),
252
'b':(('', 'b', 'b-id'), [
266
'b': (('', 'b', 'b-id'), [
253
267
('d', '', 0, False, null_stat),
254
268
('d', '', 0, False, revision_id),
256
'b/c':(('b', 'c', 'c-id'), [
270
'b/c': (('b', 'c', 'c-id'), [
257
271
('f', '', 0, False, null_stat),
258
272
('f', c_sha, c_len, False, revision_id),
260
'b/d':(('b', 'd', 'd-id'), [
274
'b/d': (('b', 'd', 'd-id'), [
261
275
('d', '', 0, False, null_stat),
262
276
('d', '', 0, False, revision_id),
264
'b/d/e':(('b/d', 'e', 'e-id'), [
278
'b/d/e': (('b/d', 'e', 'e-id'), [
265
279
('f', '', 0, False, null_stat),
266
280
('f', e_sha, e_len, False, revision_id),
268
'b-c':(('', 'b-c', 'b-c-id'), [
282
'b-c': (('', 'b-c', 'b-c-id'), [
269
283
('f', '', 0, False, null_stat),
270
284
('f', b_c_sha, b_c_len, False, revision_id),
272
'f':(('', 'f', 'f-id'), [
286
'f': (('', 'f', 'f-id'), [
273
287
('f', '', 0, False, null_stat),
274
288
('f', f_sha, f_len, False, revision_id),
2320
2449
self.assertTrue(len(statvalue) >= 10)
2321
2450
self.assertEqual(len(text), statvalue.st_size)
2322
2451
self.assertEqual(expected_sha, sha1)
2454
class _Repo(object):
2455
"""A minimal api to get InventoryRevisionTree to work."""
2458
default_format = controldir.format_registry.make_controldir('default')
2459
self._format = default_format.repository_format
2461
def lock_read(self):
2468
class TestUpdateBasisByDelta(tests.TestCase):
2470
def path_to_ie(self, path, file_id, rev_id, dir_ids):
2471
if path.endswith('/'):
2476
dirname, basename = osutils.split(path)
2478
dir_id = dir_ids[dirname]
2480
dir_id = osutils.basename(dirname) + '-id'
2482
ie = inventory.InventoryDirectory(file_id, basename, dir_id)
2483
dir_ids[path] = file_id
2485
ie = inventory.InventoryFile(file_id, basename, dir_id)
2488
ie.revision = rev_id
2491
def create_tree_from_shape(self, rev_id, shape):
2492
dir_ids = {'': 'root-id'}
2493
inv = inventory.Inventory('root-id', rev_id)
2496
path, file_id = info
2499
path, file_id, ie_rev_id = info
2501
# Replace the root entry
2502
del inv._byid[inv.root.file_id]
2503
inv.root.file_id = file_id
2504
inv._byid[file_id] = inv.root
2505
dir_ids[''] = file_id
2507
inv.add(self.path_to_ie(path, file_id, ie_rev_id, dir_ids))
2508
return inventorytree.InventoryRevisionTree(_Repo(), inv, rev_id)
2510
def create_empty_dirstate(self):
2511
fd, path = tempfile.mkstemp(prefix='bzr-dirstate')
2512
self.addCleanup(os.remove, path)
2514
state = dirstate.DirState.initialize(path)
2515
self.addCleanup(state.unlock)
2518
def create_inv_delta(self, delta, rev_id):
2519
"""Translate a 'delta shape' into an actual InventoryDelta"""
2520
dir_ids = {'': 'root-id'}
2522
for old_path, new_path, file_id in delta:
2523
if old_path is not None and old_path.endswith('/'):
2524
# Don't have to actually do anything for this, because only
2525
# new_path creates InventoryEntries
2526
old_path = old_path[:-1]
2527
if new_path is None: # Delete
2528
inv_delta.append((old_path, None, file_id, None))
2530
ie = self.path_to_ie(new_path, file_id, rev_id, dir_ids)
2531
inv_delta.append((old_path, new_path, file_id, ie))
2534
def assertUpdate(self, active, basis, target):
2535
"""Assert that update_basis_by_delta works how we want.
2537
Set up a DirState object with active_shape for tree 0, basis_shape for
2538
tree 1. Then apply the delta from basis_shape to target_shape,
2539
and assert that the DirState is still valid, and that its stored
2540
content matches the target_shape.
2542
active_tree = self.create_tree_from_shape('active', active)
2543
basis_tree = self.create_tree_from_shape('basis', basis)
2544
target_tree = self.create_tree_from_shape('target', target)
2545
state = self.create_empty_dirstate()
2546
state.set_state_from_scratch(active_tree.root_inventory,
2547
[('basis', basis_tree)], [])
2548
delta = target_tree.root_inventory._make_delta(
2549
basis_tree.root_inventory)
2550
state.update_basis_by_delta(delta, 'target')
2552
dirstate_tree = workingtree_4.DirStateRevisionTree(state,
2554
# The target now that delta has been applied should match the
2556
self.assertEqual([], list(dirstate_tree.iter_changes(target_tree)))
2557
# And the dirblock state should be identical to the state if we created
2559
state2 = self.create_empty_dirstate()
2560
state2.set_state_from_scratch(active_tree.root_inventory,
2561
[('target', target_tree)], [])
2562
self.assertEqual(state2._dirblocks, state._dirblocks)
2565
def assertBadDelta(self, active, basis, delta):
2566
"""Test that we raise InconsistentDelta when appropriate.
2568
:param active: The active tree shape
2569
:param basis: The basis tree shape
2570
:param delta: A description of the delta to apply. Similar to the form
2571
for regular inventory deltas, but omitting the InventoryEntry.
2572
So adding a file is: (None, 'path', b'file-id')
2573
Adding a directory is: (None, 'path/', 'dir-id')
2574
Renaming a dir is: ('old/', 'new/', 'dir-id')
2577
active_tree = self.create_tree_from_shape('active', active)
2578
basis_tree = self.create_tree_from_shape('basis', basis)
2579
inv_delta = self.create_inv_delta(delta, 'target')
2580
state = self.create_empty_dirstate()
2581
state.set_state_from_scratch(active_tree.root_inventory,
2582
[('basis', basis_tree)], [])
2583
self.assertRaises(errors.InconsistentDelta,
2584
state.update_basis_by_delta, inv_delta, 'target')
2586
## state.update_basis_by_delta(inv_delta, 'target')
2587
## except errors.InconsistentDelta, e:
2588
## import pdb; pdb.set_trace()
2590
## import pdb; pdb.set_trace()
2591
self.assertTrue(state._changes_aborted)
2593
def test_remove_file_matching_active_state(self):
2594
state = self.assertUpdate(
2596
basis =[('file', b'file-id')],
2600
def test_remove_file_present_in_active_state(self):
2601
state = self.assertUpdate(
2602
active=[('file', b'file-id')],
2603
basis =[('file', b'file-id')],
2607
def test_remove_file_present_elsewhere_in_active_state(self):
2608
state = self.assertUpdate(
2609
active=[('other-file', b'file-id')],
2610
basis =[('file', b'file-id')],
2614
def test_remove_file_active_state_has_diff_file(self):
2615
state = self.assertUpdate(
2616
active=[('file', b'file-id-2')],
2617
basis =[('file', b'file-id')],
2621
def test_remove_file_active_state_has_diff_file_and_file_elsewhere(self):
2622
state = self.assertUpdate(
2623
active=[('file', b'file-id-2'),
2624
('other-file', b'file-id')],
2625
basis =[('file', b'file-id')],
2629
def test_add_file_matching_active_state(self):
2630
state = self.assertUpdate(
2631
active=[('file', b'file-id')],
2633
target=[('file', b'file-id')],
2636
def test_add_file_in_empty_dir_not_matching_active_state(self):
2637
state = self.assertUpdate(
2639
basis=[('dir/', 'dir-id')],
2640
target=[('dir/', 'dir-id', 'basis'), ('dir/file', b'file-id')],
2643
def test_add_file_missing_in_active_state(self):
2644
state = self.assertUpdate(
2647
target=[('file', b'file-id')],
2650
def test_add_file_elsewhere_in_active_state(self):
2651
state = self.assertUpdate(
2652
active=[('other-file', b'file-id')],
2654
target=[('file', b'file-id')],
2657
def test_add_file_active_state_has_diff_file_and_file_elsewhere(self):
2658
state = self.assertUpdate(
2659
active=[('other-file', b'file-id'),
2660
('file', b'file-id-2')],
2662
target=[('file', b'file-id')],
2665
def test_rename_file_matching_active_state(self):
2666
state = self.assertUpdate(
2667
active=[('other-file', b'file-id')],
2668
basis =[('file', b'file-id')],
2669
target=[('other-file', b'file-id')],
2672
def test_rename_file_missing_in_active_state(self):
2673
state = self.assertUpdate(
2675
basis =[('file', b'file-id')],
2676
target=[('other-file', b'file-id')],
2679
def test_rename_file_present_elsewhere_in_active_state(self):
2680
state = self.assertUpdate(
2681
active=[('third', b'file-id')],
2682
basis =[('file', b'file-id')],
2683
target=[('other-file', b'file-id')],
2686
def test_rename_file_active_state_has_diff_source_file(self):
2687
state = self.assertUpdate(
2688
active=[('file', b'file-id-2')],
2689
basis =[('file', b'file-id')],
2690
target=[('other-file', b'file-id')],
2693
def test_rename_file_active_state_has_diff_target_file(self):
2694
state = self.assertUpdate(
2695
active=[('other-file', b'file-id-2')],
2696
basis =[('file', b'file-id')],
2697
target=[('other-file', b'file-id')],
2700
def test_rename_file_active_has_swapped_files(self):
2701
state = self.assertUpdate(
2702
active=[('file', b'file-id'),
2703
('other-file', b'file-id-2')],
2704
basis= [('file', b'file-id'),
2705
('other-file', b'file-id-2')],
2706
target=[('file', b'file-id-2'),
2707
('other-file', b'file-id')])
2709
def test_rename_file_basis_has_swapped_files(self):
2710
state = self.assertUpdate(
2711
active=[('file', b'file-id'),
2712
('other-file', b'file-id-2')],
2713
basis= [('file', b'file-id-2'),
2714
('other-file', b'file-id')],
2715
target=[('file', b'file-id'),
2716
('other-file', b'file-id-2')])
2718
def test_rename_directory_with_contents(self):
2719
state = self.assertUpdate( # active matches basis
2720
active=[('dir1/', 'dir-id'),
2721
('dir1/file', b'file-id')],
2722
basis= [('dir1/', 'dir-id'),
2723
('dir1/file', b'file-id')],
2724
target=[('dir2/', 'dir-id'),
2725
('dir2/file', b'file-id')])
2726
state = self.assertUpdate( # active matches target
2727
active=[('dir2/', 'dir-id'),
2728
('dir2/file', b'file-id')],
2729
basis= [('dir1/', 'dir-id'),
2730
('dir1/file', b'file-id')],
2731
target=[('dir2/', 'dir-id'),
2732
('dir2/file', b'file-id')])
2733
state = self.assertUpdate( # active empty
2735
basis= [('dir1/', 'dir-id'),
2736
('dir1/file', b'file-id')],
2737
target=[('dir2/', 'dir-id'),
2738
('dir2/file', b'file-id')])
2739
state = self.assertUpdate( # active present at other location
2740
active=[('dir3/', 'dir-id'),
2741
('dir3/file', b'file-id')],
2742
basis= [('dir1/', 'dir-id'),
2743
('dir1/file', b'file-id')],
2744
target=[('dir2/', 'dir-id'),
2745
('dir2/file', b'file-id')])
2746
state = self.assertUpdate( # active has different ids
2747
active=[('dir1/', 'dir1-id'),
2748
('dir1/file', 'file1-id'),
2749
('dir2/', 'dir2-id'),
2750
('dir2/file', 'file2-id')],
2751
basis= [('dir1/', 'dir-id'),
2752
('dir1/file', b'file-id')],
2753
target=[('dir2/', 'dir-id'),
2754
('dir2/file', b'file-id')])
2756
def test_invalid_file_not_present(self):
2757
state = self.assertBadDelta(
2758
active=[('file', b'file-id')],
2759
basis= [('file', b'file-id')],
2760
delta=[('other-file', 'file', b'file-id')])
2762
def test_invalid_new_id_same_path(self):
2763
# The bad entry comes after
2764
state = self.assertBadDelta(
2765
active=[('file', b'file-id')],
2766
basis= [('file', b'file-id')],
2767
delta=[(None, 'file', b'file-id-2')])
2768
# The bad entry comes first
2769
state = self.assertBadDelta(
2770
active=[('file', b'file-id-2')],
2771
basis=[('file', b'file-id-2')],
2772
delta=[(None, 'file', b'file-id')])
2774
def test_invalid_existing_id(self):
2775
state = self.assertBadDelta(
2776
active=[('file', b'file-id')],
2777
basis= [('file', b'file-id')],
2778
delta=[(None, 'file', b'file-id')])
2780
def test_invalid_parent_missing(self):
2781
state = self.assertBadDelta(
2784
delta=[(None, 'path/path2', b'file-id')])
2785
# Note: we force the active tree to have the directory, by knowing how
2786
# path_to_ie handles entries with missing parents
2787
state = self.assertBadDelta(
2788
active=[('path/', 'path-id')],
2790
delta=[(None, 'path/path2', b'file-id')])
2791
state = self.assertBadDelta(
2792
active=[('path/', 'path-id'),
2793
('path/path2', b'file-id')],
2795
delta=[(None, 'path/path2', b'file-id')])
2797
def test_renamed_dir_same_path(self):
2798
# We replace the parent directory, with another parent dir. But the C
2799
# file doesn't look like it has been moved.
2800
state = self.assertUpdate(# Same as basis
2801
active=[('dir/', 'A-id'),
2803
basis= [('dir/', 'A-id'),
2805
target=[('dir/', 'C-id'),
2807
state = self.assertUpdate(# Same as target
2808
active=[('dir/', 'C-id'),
2810
basis= [('dir/', 'A-id'),
2812
target=[('dir/', 'C-id'),
2814
state = self.assertUpdate(# empty active
2816
basis= [('dir/', 'A-id'),
2818
target=[('dir/', 'C-id'),
2820
state = self.assertUpdate(# different active
2821
active=[('dir/', 'D-id'),
2823
basis= [('dir/', 'A-id'),
2825
target=[('dir/', 'C-id'),
2828
def test_parent_child_swap(self):
2829
state = self.assertUpdate(# Same as basis
2830
active=[('A/', 'A-id'),
2833
basis= [('A/', 'A-id'),
2836
target=[('A/', 'B-id'),
2839
state = self.assertUpdate(# Same as target
2840
active=[('A/', 'B-id'),
2843
basis= [('A/', 'A-id'),
2846
target=[('A/', 'B-id'),
2849
state = self.assertUpdate(# empty active
2851
basis= [('A/', 'A-id'),
2854
target=[('A/', 'B-id'),
2857
state = self.assertUpdate(# different active
2858
active=[('D/', 'A-id'),
2861
basis= [('A/', 'A-id'),
2864
target=[('A/', 'B-id'),
2868
def test_change_root_id(self):
2869
state = self.assertUpdate( # same as basis
2870
active=[('', 'root-id'),
2871
('file', b'file-id')],
2872
basis= [('', 'root-id'),
2873
('file', b'file-id')],
2874
target=[('', 'target-root-id'),
2875
('file', b'file-id')])
2876
state = self.assertUpdate( # same as target
2877
active=[('', 'target-root-id'),
2878
('file', b'file-id')],
2879
basis= [('', 'root-id'),
2880
('file', b'file-id')],
2881
target=[('', 'target-root-id'),
2882
('file', 'root-id')])
2883
state = self.assertUpdate( # all different
2884
active=[('', 'active-root-id'),
2885
('file', b'file-id')],
2886
basis= [('', 'root-id'),
2887
('file', b'file-id')],
2888
target=[('', 'target-root-id'),
2889
('file', 'root-id')])
2891
def test_change_file_absent_in_active(self):
2892
state = self.assertUpdate(
2894
basis= [('file', b'file-id')],
2895
target=[('file', b'file-id')])
2897
def test_invalid_changed_file(self):
2898
state = self.assertBadDelta( # Not present in basis
2899
active=[('file', b'file-id')],
2901
delta=[('file', 'file', b'file-id')])
2902
state = self.assertBadDelta( # present at another location in basis
2903
active=[('file', b'file-id')],
2904
basis= [('other-file', b'file-id')],
2905
delta=[('file', 'file', b'file-id')])