2586
2587
self.assertEqual(False, preview_tree.is_executable('baz-id'))
2590
class FakeSerializer(object):
2591
"""Serializer implementation that simply returns the input.
2593
The input is returned in the order used by pack.ContainerPushParser.
2596
def bytes_record(bytes, names):
2589
2600
class TestSerializeTransform(tests.TestCaseWithTransport):
2591
def get_two_previews(self, tree):
2602
def get_preview(self, tree=None):
2604
tree = self.make_branch_and_tree('tree')
2592
2605
tt = TransformPreview(tree)
2593
2606
self.addCleanup(tt.finalize)
2594
tt2 = TransformPreview(tree)
2595
self.addCleanup(tt2.finalize)
2609
def assertSerializesTo(self, expected, tt):
2610
records = list(tt.serialize(FakeSerializer()))
2611
self.assertEqual(expected, records)
2599
def reserialize(tt, tt2):
2600
serializer = pack.ContainerSerialiser()
2601
parser = pack.ContainerPushParser()
2602
parser.accept_bytes(serializer.begin())
2603
for bytes in tt.serialize(serializer):
2604
parser.accept_bytes(bytes)
2605
parser.accept_bytes(serializer.end())
2606
tt2.deserialize(iter(parser.read_pending_records()))
2608
def test_roundtrip_creation(self):
2609
tree = self.make_branch_and_tree('.')
2610
tt, tt2 = self.get_two_previews(tree)
2614
def default_attribs():
2619
'_new_executability': {},
2621
'_tree_path_ids': {'': 'new-0'},
2623
'_removed_contents': [],
2624
'_non_present_ids': {},
2627
def make_records(self, attribs, contents):
2629
(((('attribs'),),), bencode.bencode(attribs))]
2630
records.extend([(((n, k),), c) for n, k, c in contents])
2633
def creation_records(self):
2634
attribs = self.default_attribs()
2635
attribs['_id_number'] = 3
2636
attribs['_new_name'] = {
2637
'new-1': u'foo\u1234'.encode('utf-8'), 'new-2': 'qux'}
2638
attribs['_new_id'] = {'new-1': 'baz', 'new-2': 'quxx'}
2639
attribs['_new_parent'] = {'new-1': 'new-0', 'new-2': 'new-0'}
2640
attribs['_new_executability'] = {'new-1': 1}
2642
('new-1', 'file', 'i 1\nbar\n'),
2643
('new-2', 'directory', ''),
2645
return self.make_records(attribs, contents)
2647
def test_serialize_creation(self):
2648
tt = self.get_preview()
2611
2649
tt.new_file(u'foo\u1234', tt.root, 'bar', 'baz', True)
2612
2650
tt.new_directory('qux', tt.root, 'quxx')
2613
self.reserialize(tt, tt2)
2614
self.assertEqual(3, tt2._id_number)
2651
records = tt.serialize(FakeSerializer())
2652
self.assertEqual(self.creation_records(), list(records))
2654
def test_deserialize_creation(self):
2655
tt = self.get_preview()
2656
tt.deserialize(iter(self.creation_records()))
2657
self.assertEqual(3, tt._id_number)
2615
2658
self.assertEqual({'new-1': u'foo\u1234',
2616
'new-2': 'qux'}, tt2._new_name)
2617
self.assertEqual({'new-1': 'baz', 'new-2': 'quxx'}, tt2._new_id)
2618
self.assertEqual({'new-1': tt.root, 'new-2': tt.root}, tt2._new_parent)
2619
self.assertEqual({'baz': 'new-1', 'quxx': 'new-2'}, tt2._r_new_id)
2620
self.assertEqual({'new-1': True}, tt2._new_executability)
2659
'new-2': 'qux'}, tt._new_name)
2660
self.assertEqual({'new-1': 'baz', 'new-2': 'quxx'}, tt._new_id)
2661
self.assertEqual({'new-1': tt.root, 'new-2': tt.root}, tt._new_parent)
2662
self.assertEqual({'baz': 'new-1', 'quxx': 'new-2'}, tt._r_new_id)
2663
self.assertEqual({'new-1': True}, tt._new_executability)
2621
2664
self.assertEqual({'new-1': 'file',
2622
'new-2': 'directory'}, tt2._new_contents)
2623
foo_limbo = open(tt2._limbo_name('new-1'), 'rb')
2665
'new-2': 'directory'}, tt._new_contents)
2666
foo_limbo = open(tt._limbo_name('new-1'), 'rb')
2625
2668
foo_content = foo_limbo.read()
2627
2670
foo_limbo.close()
2628
2671
self.assertEqual('bar', foo_content)
2630
def test_symlink_creation(self):
2673
def symlink_creation_records(self):
2674
attribs = self.default_attribs()
2675
attribs['_id_number'] = 2
2676
attribs['_new_name'] = {'new-1': u'foo\u1234'.encode('utf-8')}
2677
attribs['_new_parent'] = {'new-1': 'new-0'}
2678
contents = [('new-1', 'symlink', u'bar\u1234'.encode('utf-8'))]
2679
return self.make_records(attribs, contents)
2681
def test_serialize_symlink_creation(self):
2631
2682
self.requireFeature(tests.SymlinkFeature)
2632
tree = self.make_branch_and_tree('.')
2633
tt, tt2 = self.get_two_previews(tree)
2634
tt.new_symlink('foo', tt.root, 'bar')
2635
self.reserialize(tt, tt2)
2636
foo_content = os.readlink(tt2._limbo_name('new-1'))
2637
self.assertEqual('bar', foo_content)
2639
def test_roundtrip_destruction(self):
2683
tt = self.get_preview()
2684
tt.new_symlink(u'foo\u1234', tt.root, u'bar\u1234')
2685
records = tt.serialize(FakeSerializer())
2686
self.assertEqual(self.symlink_creation_records(), list(records))
2688
def test_deserialize_symlink_creation(self):
2689
tt = self.get_preview()
2690
tt.deserialize(iter(self.symlink_creation_records()))
2691
foo_content = os.readlink(tt._limbo_name('new-1'))
2692
self.assertEqual(u'bar\u1234'.encode('utf-8'), foo_content)
2694
def make_destruction_preview(self):
2640
2695
tree = self.make_branch_and_tree('.')
2641
2696
self.build_tree([u'foo\u1234', 'bar'])
2642
2697
tree.add([u'foo\u1234', 'bar'], ['foo-id', 'bar-id'])
2643
tt, tt2 = self.get_two_previews(tree)
2698
return self.get_preview(tree)
2700
def destruction_records(self):
2701
attribs = self.default_attribs()
2702
attribs['_id_number'] = 3
2703
attribs['_removed_id'] = ['new-1']
2704
attribs['_removed_contents'] = ['new-2']
2705
attribs['_tree_path_ids'] = {
2707
u'foo\u1234'.encode('utf-8'): 'new-1',
2710
return self.make_records(attribs, [])
2712
def test_serialize_destruction(self):
2713
tt = self.make_destruction_preview()
2644
2714
foo_trans_id = tt.trans_id_tree_file_id('foo-id')
2645
2715
tt.unversion_file(foo_trans_id)
2646
2716
bar_trans_id = tt.trans_id_tree_file_id('bar-id')
2647
2717
tt.delete_contents(bar_trans_id)
2648
self.reserialize(tt, tt2)
2649
self.assertEqual({u'foo\u1234': foo_trans_id,
2650
'bar': bar_trans_id,
2651
'': tt.root}, tt2._tree_path_ids)
2652
self.assertEqual({foo_trans_id: u'foo\u1234',
2653
bar_trans_id: 'bar',
2654
tt.root: ''}, tt2._tree_id_paths)
2655
self.assertEqual(set([foo_trans_id]), tt2._removed_id)
2656
self.assertEqual(set([bar_trans_id]), tt2._removed_contents)
2658
def test_roundtrip_missing(self):
2659
tree = self.make_branch_and_tree('.')
2660
tt, tt2 = self.get_two_previews(tree)
2718
self.assertSerializesTo(self.destruction_records(), tt)
2720
def test_deserialize_destruction(self):
2721
tt = self.make_destruction_preview()
2722
tt.deserialize(iter(self.destruction_records()))
2723
self.assertEqual({u'foo\u1234': 'new-1',
2725
'': tt.root}, tt._tree_path_ids)
2726
self.assertEqual({'new-1': u'foo\u1234',
2728
tt.root: ''}, tt._tree_id_paths)
2729
self.assertEqual(set(['new-1']), tt._removed_id)
2730
self.assertEqual(set(['new-2']), tt._removed_contents)
2732
def missing_records(self):
2733
attribs = self.default_attribs()
2734
attribs['_id_number'] = 2
2735
attribs['_non_present_ids'] = {
2737
return self.make_records(attribs, [])
2739
def test_serialize_missing(self):
2740
tt = self.get_preview()
2661
2741
boo_trans_id = tt.trans_id_file_id('boo')
2662
self.reserialize(tt, tt2)
2663
self.assertEqual({'boo': boo_trans_id}, tt2._non_present_ids)
2665
def test_roundtrip_modification(self):
2742
self.assertSerializesTo(self.missing_records(), tt)
2744
def test_deserialize_missing(self):
2745
tt = self.get_preview()
2746
tt.deserialize(iter(self.missing_records()))
2747
self.assertEqual({'boo': 'new-1'}, tt._non_present_ids)
2749
def make_modification_preview(self):
2666
2750
LINES_ONE = 'aa\nbb\ncc\ndd\n'
2667
2751
LINES_TWO = 'z\nbb\nx\ndd\n'
2668
2752
tree = self.make_branch_and_tree('tree')
2669
2753
self.build_tree_contents([('tree/file', LINES_ONE)])
2670
2754
tree.add('file', 'file-id')
2671
tt, tt2 = self.get_two_previews(tree)
2755
return self.get_preview(tree), LINES_TWO
2757
def modification_records(self):
2758
attribs = self.default_attribs()
2759
attribs['_id_number'] = 2
2760
attribs['_tree_path_ids'] = {
2763
attribs['_removed_contents'] = ['new-1']
2764
contents = [('new-1', 'file',
2765
'i 1\nz\n\nc 0 1 1 1\ni 1\nx\n\nc 0 3 3 1\n')]
2766
return self.make_records(attribs, contents)
2768
def test_serialize_modification(self):
2769
tt, LINES = self.make_modification_preview()
2672
2770
trans_id = tt.trans_id_file_id('file-id')
2673
2771
tt.delete_contents(trans_id)
2674
tt.create_file(LINES_TWO, trans_id)
2675
self.reserialize(tt, tt2)
2676
self.assertFileEqual(LINES_TWO, tt2._limbo_name(trans_id))
2678
def test_roundtrip_kind_change(self):
2679
LINES_ONE = 'a\nb\nc\nd\n'
2772
tt.create_file(LINES, trans_id)
2773
self.assertSerializesTo(self.modification_records(), tt)
2775
def test_deserialize_modification(self):
2776
tt, LINES = self.make_modification_preview()
2777
tt.deserialize(iter(self.modification_records()))
2778
self.assertFileEqual(LINES, tt._limbo_name('new-1'))
2780
def make_kind_change_preview(self):
2781
LINES = 'a\nb\nc\nd\n'
2680
2782
tree = self.make_branch_and_tree('tree')
2681
2783
self.build_tree(['tree/foo/'])
2682
2784
tree.add('foo', 'foo-id')
2683
tt, tt2 = self.get_two_previews(tree)
2785
return self.get_preview(tree), LINES
2787
def kind_change_records(self):
2788
attribs = self.default_attribs()
2789
attribs['_id_number'] = 2
2790
attribs['_tree_path_ids'] = {
2793
attribs['_removed_contents'] = ['new-1']
2794
contents = [('new-1', 'file',
2795
'i 4\na\nb\nc\nd\n\n')]
2796
return self.make_records(attribs, contents)
2798
def test_serialize_kind_change(self):
2799
tt, LINES = self.make_kind_change_preview()
2684
2800
trans_id = tt.trans_id_file_id('foo-id')
2685
2801
tt.delete_contents(trans_id)
2686
tt.create_file(LINES_ONE, trans_id)
2687
self.reserialize(tt, tt2)
2688
self.assertFileEqual(LINES_ONE, tt2._limbo_name(trans_id))
2690
def test_roundtrip_add_contents(self):
2691
LINES_ONE = 'a\nb\nc\nd\n'
2802
tt.create_file(LINES, trans_id)
2803
self.assertSerializesTo(self.kind_change_records(), tt)
2805
def test_deserialize_kind_change(self):
2806
tt, LINES = self.make_kind_change_preview()
2807
tt.deserialize(iter(self.kind_change_records()))
2808
self.assertFileEqual(LINES, tt._limbo_name('new-1'))
2810
def make_add_contents_preview(self):
2811
LINES = 'a\nb\nc\nd\n'
2692
2812
tree = self.make_branch_and_tree('tree')
2693
2813
self.build_tree(['tree/foo'])
2694
2814
tree.add('foo')
2695
2815
os.unlink('tree/foo')
2696
tt, tt2 = self.get_two_previews(tree)
2816
return self.get_preview(tree), LINES
2818
def add_contents_records(self):
2819
attribs = self.default_attribs()
2820
attribs['_id_number'] = 2
2821
attribs['_tree_path_ids'] = {
2824
contents = [('new-1', 'file',
2825
'i 4\na\nb\nc\nd\n\n')]
2826
return self.make_records(attribs, contents)
2828
def test_serialize_add_contents(self):
2829
tt, LINES = self.make_add_contents_preview()
2697
2830
trans_id = tt.trans_id_tree_path('foo')
2698
tt.create_file(LINES_ONE, trans_id)
2699
self.reserialize(tt, tt2)
2700
self.assertFileEqual(LINES_ONE, tt2._limbo_name(trans_id))
2831
tt.create_file(LINES, trans_id)
2832
self.assertSerializesTo(self.add_contents_records(), tt)
2834
def test_deserialize_add_contents(self):
2835
tt, LINES = self.make_add_contents_preview()
2836
tt.deserialize(iter(self.add_contents_records()))
2837
self.assertFileEqual(LINES, tt._limbo_name('new-1'))
2702
2839
def test_get_parents_lines(self):
2703
2840
LINES_ONE = 'aa\nbb\ncc\ndd\n'