682
682
self.check_read_write(k)
685
class MergeCases(TestBase):
686
def doMerge(self, base, a, b, mp):
687
from cStringIO import StringIO
688
from textwrap import dedent
694
w.add_lines('text0', [], map(addcrlf, base))
695
w.add_lines('text1', ['text0'], map(addcrlf, a))
696
w.add_lines('text2', ['text0'], map(addcrlf, b))
698
self.log('weave is:')
701
self.log(tmpf.getvalue())
703
self.log('merge plan:')
704
p = list(w.plan_merge('text1', 'text2'))
705
for state, line in p:
707
self.log('%12s | %s' % (state, line[:-1]))
711
mt.writelines(w.weave_merge(p))
713
self.log(mt.getvalue())
715
mp = map(addcrlf, mp)
716
self.assertEqual(mt.readlines(), mp)
719
def testOneInsert(self):
725
def testSeparateInserts(self):
726
self.doMerge(['aaa', 'bbb', 'ccc'],
727
['aaa', 'xxx', 'bbb', 'ccc'],
728
['aaa', 'bbb', 'yyy', 'ccc'],
729
['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
731
def testSameInsert(self):
732
self.doMerge(['aaa', 'bbb', 'ccc'],
733
['aaa', 'xxx', 'bbb', 'ccc'],
734
['aaa', 'xxx', 'bbb', 'yyy', 'ccc'],
735
['aaa', 'xxx', 'bbb', 'yyy', 'ccc'])
737
def testOverlappedInsert(self):
738
self.doMerge(['aaa', 'bbb'],
739
['aaa', 'xxx', 'yyy', 'bbb'],
740
['aaa', 'xxx', 'bbb'],
741
['aaa', '<<<<<<< ', 'xxx', 'yyy', '=======', 'xxx',
744
# really it ought to reduce this to
745
# ['aaa', 'xxx', 'yyy', 'bbb']
748
def testClashReplace(self):
749
self.doMerge(['aaa'],
752
['<<<<<<< ', 'xxx', '=======', 'yyy', 'zzz',
755
def testNonClashInsert(self):
756
self.doMerge(['aaa'],
759
['<<<<<<< ', 'xxx', 'aaa', '=======', 'yyy', 'zzz',
762
self.doMerge(['aaa'],
768
def testDeleteAndModify(self):
769
"""Clashing delete and modification.
771
If one side modifies a region and the other deletes it then
772
there should be a conflict with one side blank.
775
#######################################
776
# skippd, not working yet
779
self.doMerge(['aaa', 'bbb', 'ccc'],
780
['aaa', 'ddd', 'ccc'],
782
['<<<<<<<< ', 'aaa', '=======', '>>>>>>> ', 'ccc'])
784
def _test_merge_from_strings(self, base, a, b, expected):
786
w.add_lines('text0', [], base.splitlines(True))
787
w.add_lines('text1', ['text0'], a.splitlines(True))
788
w.add_lines('text2', ['text0'], b.splitlines(True))
789
self.log('merge plan:')
790
p = list(w.plan_merge('text1', 'text2'))
791
for state, line in p:
793
self.log('%12s | %s' % (state, line[:-1]))
794
self.log('merge result:')
795
result_text = ''.join(w.weave_merge(p))
796
self.log(result_text)
797
self.assertEqualDiff(result_text, expected)
799
def test_weave_merge_conflicts(self):
800
# does weave merge properly handle plans that end with unchanged?
801
result = ''.join(Weave().weave_merge([('new-a', 'hello\n')]))
802
self.assertEqual(result, 'hello\n')
804
def test_deletion_extended(self):
805
"""One side deletes, the other deletes more.
822
self._test_merge_from_strings(base, a, b, result)
824
def test_deletion_overlap(self):
825
"""Delete overlapping regions with no other conflict.
827
Arguably it'd be better to treat these as agreement, rather than
828
conflict, but for now conflict is safer.
856
self._test_merge_from_strings(base, a, b, result)
858
def test_agreement_deletion(self):
859
"""Agree to delete some lines, without conflicts."""
881
self._test_merge_from_strings(base, a, b, result)
883
def test_sync_on_deletion(self):
884
"""Specific case of merge where we can synchronize incorrectly.
886
A previous version of the weave merge concluded that the two versions
887
agreed on deleting line 2, and this could be a synchronization point.
888
Line 1 was then considered in isolation, and thought to be deleted on
891
It's better to consider the whole thing as a disagreement region.
902
a's replacement line 2
915
a's replacement line 2
922
self._test_merge_from_strings(base, a, b, result)
925
685
class JoinWeavesTests(TestBase):
927
687
super(JoinWeavesTests, self).setUp()