mirror of
https://github.com/facebook/sapling.git
synced 2024-10-16 19:57:18 +03:00
dfda82e492
Summary: Mostly empty lines removed and added. A few bugfixes on excessive line splitting. Reviewed By: quark-zju Differential Revision: D8199128 fbshipit-source-id: 90c1616061bfd7cfbba0b75f03f89683340374d5
346 lines
10 KiB
Python
346 lines
10 KiB
Python
# Copyright (C) 2004, 2005 Canonical Ltd
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
from __future__ import absolute_import
|
|
|
|
import unittest
|
|
|
|
from mercurial import error, simplemerge, util
|
|
|
|
|
|
TestCase = unittest.TestCase
|
|
# bzr compatible interface, for the tests
|
|
class Merge3(simplemerge.Merge3Text):
|
|
"""3-way merge of texts.
|
|
|
|
Given BASE, OTHER, THIS, tries to produce a combined text
|
|
incorporating the changes from both BASE->OTHER and BASE->THIS.
|
|
All three will typically be sequences of lines."""
|
|
|
|
def __init__(self, base, a, b):
|
|
basetext = "\n".join([i.strip("\n") for i in base] + [""])
|
|
atext = "\n".join([i.strip("\n") for i in a] + [""])
|
|
btext = "\n".join([i.strip("\n") for i in b] + [""])
|
|
if util.binary(basetext) or util.binary(atext) or util.binary(btext):
|
|
raise error.Abort("don't know how to merge binary files")
|
|
simplemerge.Merge3Text.__init__(self, basetext, atext, btext, base, a, b)
|
|
|
|
|
|
CantReprocessAndShowBase = simplemerge.CantReprocessAndShowBase
|
|
|
|
|
|
def split_lines(t):
|
|
return util.stringio(t).readlines()
|
|
|
|
|
|
############################################################
|
|
# test case data from the gnu diffutils manual
|
|
# common base
|
|
TZU = split_lines(
|
|
""" The Nameless is the origin of Heaven and Earth;
|
|
The named is the mother of all things.
|
|
|
|
Therefore let there always be non-being,
|
|
so we may see their subtlety,
|
|
And let there always be being,
|
|
so we may see their outcome.
|
|
The two are the same,
|
|
But after they are produced,
|
|
they have different names.
|
|
They both may be called deep and profound.
|
|
Deeper and more profound,
|
|
The door of all subtleties!
|
|
"""
|
|
)
|
|
|
|
LAO = split_lines(
|
|
""" The Way that can be told of is not the eternal Way;
|
|
The name that can be named is not the eternal name.
|
|
The Nameless is the origin of Heaven and Earth;
|
|
The Named is the mother of all things.
|
|
Therefore let there always be non-being,
|
|
so we may see their subtlety,
|
|
And let there always be being,
|
|
so we may see their outcome.
|
|
The two are the same,
|
|
But after they are produced,
|
|
they have different names.
|
|
"""
|
|
)
|
|
|
|
|
|
TAO = split_lines(
|
|
""" The Way that can be told of is not the eternal Way;
|
|
The name that can be named is not the eternal name.
|
|
The Nameless is the origin of Heaven and Earth;
|
|
The named is the mother of all things.
|
|
|
|
Therefore let there always be non-being,
|
|
so we may see their subtlety,
|
|
And let there always be being,
|
|
so we may see their result.
|
|
The two are the same,
|
|
But after they are produced,
|
|
they have different names.
|
|
|
|
-- The Way of Lao-Tzu, tr. Wing-tsit Chan
|
|
|
|
"""
|
|
)
|
|
|
|
MERGED_RESULT = split_lines(
|
|
"""\
|
|
The Way that can be told of is not the eternal Way;
|
|
The name that can be named is not the eternal name.
|
|
The Nameless is the origin of Heaven and Earth;
|
|
The Named is the mother of all things.
|
|
Therefore let there always be non-being,
|
|
so we may see their subtlety,
|
|
And let there always be being,
|
|
so we may see their result.
|
|
The two are the same,
|
|
But after they are produced,
|
|
they have different names.
|
|
<<<<<<< LAO
|
|
=======
|
|
|
|
-- The Way of Lao-Tzu, tr. Wing-tsit Chan
|
|
|
|
>>>>>>> TAO
|
|
"""
|
|
)
|
|
|
|
|
|
class TestMerge3(TestCase):
|
|
def log(self, msg):
|
|
pass
|
|
|
|
def test_no_changes(self):
|
|
"""No conflicts because nothing changed"""
|
|
m3 = Merge3(["aaa", "bbb"], ["aaa", "bbb"], ["aaa", "bbb"])
|
|
|
|
self.assertEquals(m3.find_unconflicted(), [(0, 2)])
|
|
|
|
self.assertEquals(
|
|
list(m3.find_sync_regions()), [(0, 2, 0, 2, 0, 2), (2, 2, 2, 2, 2, 2)]
|
|
)
|
|
|
|
self.assertEquals(list(m3.merge_regions()), [("unchanged", 0, 2)])
|
|
|
|
self.assertEquals(list(m3.merge_groups()), [("unchanged", ["aaa", "bbb"])])
|
|
|
|
def test_front_insert(self):
|
|
m3 = Merge3(["zz"], ["aaa", "bbb", "zz"], ["zz"])
|
|
|
|
# todo: should use a sentinel at end as from get_matching_blocks
|
|
# to match without zz
|
|
self.assertEquals(
|
|
list(m3.find_sync_regions()), [(0, 1, 2, 3, 0, 1), (1, 1, 3, 3, 1, 1)]
|
|
)
|
|
|
|
self.assertEquals(list(m3.merge_regions()), [("a", 0, 2), ("unchanged", 0, 1)])
|
|
|
|
self.assertEquals(
|
|
list(m3.merge_groups()), [("a", ["aaa", "bbb"]), ("unchanged", ["zz"])]
|
|
)
|
|
|
|
def test_null_insert(self):
|
|
m3 = Merge3([], ["aaa", "bbb"], [])
|
|
# todo: should use a sentinel at end as from get_matching_blocks
|
|
# to match without zz
|
|
self.assertEquals(list(m3.find_sync_regions()), [(0, 0, 2, 2, 0, 0)])
|
|
|
|
self.assertEquals(list(m3.merge_regions()), [("a", 0, 2)])
|
|
|
|
self.assertEquals(list(m3.merge_lines()), ["aaa", "bbb"])
|
|
|
|
def test_no_conflicts(self):
|
|
"""No conflicts because only one side changed"""
|
|
m3 = Merge3(["aaa", "bbb"], ["aaa", "111", "bbb"], ["aaa", "bbb"])
|
|
|
|
self.assertEquals(m3.find_unconflicted(), [(0, 1), (1, 2)])
|
|
|
|
self.assertEquals(
|
|
list(m3.find_sync_regions()),
|
|
[(0, 1, 0, 1, 0, 1), (1, 2, 2, 3, 1, 2), (2, 2, 3, 3, 2, 2)],
|
|
)
|
|
|
|
self.assertEquals(
|
|
list(m3.merge_regions()),
|
|
[("unchanged", 0, 1), ("a", 1, 2), ("unchanged", 1, 2)],
|
|
)
|
|
|
|
def test_append_a(self):
|
|
m3 = Merge3(["aaa\n", "bbb\n"], ["aaa\n", "bbb\n", "222\n"], ["aaa\n", "bbb\n"])
|
|
|
|
self.assertEquals("".join(m3.merge_lines()), "aaa\nbbb\n222\n")
|
|
|
|
def test_append_b(self):
|
|
m3 = Merge3(["aaa\n", "bbb\n"], ["aaa\n", "bbb\n"], ["aaa\n", "bbb\n", "222\n"])
|
|
|
|
self.assertEquals("".join(m3.merge_lines()), "aaa\nbbb\n222\n")
|
|
|
|
def test_append_agreement(self):
|
|
m3 = Merge3(
|
|
["aaa\n", "bbb\n"], ["aaa\n", "bbb\n", "222\n"], ["aaa\n", "bbb\n", "222\n"]
|
|
)
|
|
|
|
self.assertEquals("".join(m3.merge_lines()), "aaa\nbbb\n222\n")
|
|
|
|
def test_append_clash(self):
|
|
m3 = Merge3(
|
|
["aaa\n", "bbb\n"], ["aaa\n", "bbb\n", "222\n"], ["aaa\n", "bbb\n", "333\n"]
|
|
)
|
|
|
|
ml = m3.merge_lines(
|
|
name_a="a", name_b="b", start_marker="<<", mid_marker="--", end_marker=">>"
|
|
)
|
|
self.assertEquals(
|
|
"".join(ml), "aaa\n" "bbb\n" "<< a\n" "222\n" "--\n" "333\n" ">> b\n"
|
|
)
|
|
|
|
def test_insert_agreement(self):
|
|
m3 = Merge3(
|
|
["aaa\n", "bbb\n"], ["aaa\n", "222\n", "bbb\n"], ["aaa\n", "222\n", "bbb\n"]
|
|
)
|
|
|
|
ml = m3.merge_lines(
|
|
name_a="a", name_b="b", start_marker="<<", mid_marker="--", end_marker=">>"
|
|
)
|
|
self.assertEquals("".join(ml), "aaa\n222\nbbb\n")
|
|
|
|
def test_insert_clash(self):
|
|
"""Both try to insert lines in the same place."""
|
|
m3 = Merge3(
|
|
["aaa\n", "bbb\n"], ["aaa\n", "111\n", "bbb\n"], ["aaa\n", "222\n", "bbb\n"]
|
|
)
|
|
|
|
self.assertEquals(m3.find_unconflicted(), [(0, 1), (1, 2)])
|
|
|
|
self.assertEquals(
|
|
list(m3.find_sync_regions()),
|
|
[(0, 1, 0, 1, 0, 1), (1, 2, 2, 3, 2, 3), (2, 2, 3, 3, 3, 3)],
|
|
)
|
|
|
|
self.assertEquals(
|
|
list(m3.merge_regions()),
|
|
[("unchanged", 0, 1), ("conflict", 1, 1, 1, 2, 1, 2), ("unchanged", 1, 2)],
|
|
)
|
|
|
|
self.assertEquals(
|
|
list(m3.merge_groups()),
|
|
[
|
|
("unchanged", ["aaa\n"]),
|
|
("conflict", [], ["111\n"], ["222\n"]),
|
|
("unchanged", ["bbb\n"]),
|
|
],
|
|
)
|
|
|
|
ml = m3.merge_lines(
|
|
name_a="a", name_b="b", start_marker="<<", mid_marker="--", end_marker=">>"
|
|
)
|
|
self.assertEquals(
|
|
"".join(ml),
|
|
"""aaa
|
|
<< a
|
|
111
|
|
--
|
|
222
|
|
>> b
|
|
bbb
|
|
""",
|
|
)
|
|
|
|
def test_replace_clash(self):
|
|
"""Both try to insert lines in the same place."""
|
|
m3 = Merge3(["aaa", "000", "bbb"], ["aaa", "111", "bbb"], ["aaa", "222", "bbb"])
|
|
|
|
self.assertEquals(m3.find_unconflicted(), [(0, 1), (2, 3)])
|
|
|
|
self.assertEquals(
|
|
list(m3.find_sync_regions()),
|
|
[(0, 1, 0, 1, 0, 1), (2, 3, 2, 3, 2, 3), (3, 3, 3, 3, 3, 3)],
|
|
)
|
|
|
|
def test_replace_multi(self):
|
|
"""Replacement with regions of different size."""
|
|
m3 = Merge3(
|
|
["aaa", "000", "000", "bbb"],
|
|
["aaa", "111", "111", "111", "bbb"],
|
|
["aaa", "222", "222", "222", "222", "bbb"],
|
|
)
|
|
|
|
self.assertEquals(m3.find_unconflicted(), [(0, 1), (3, 4)])
|
|
|
|
self.assertEquals(
|
|
list(m3.find_sync_regions()),
|
|
[(0, 1, 0, 1, 0, 1), (3, 4, 4, 5, 5, 6), (4, 4, 5, 5, 6, 6)],
|
|
)
|
|
|
|
def test_merge_poem(self):
|
|
"""Test case from diff3 manual"""
|
|
m3 = Merge3(TZU, LAO, TAO)
|
|
ml = list(m3.merge_lines("LAO", "TAO"))
|
|
self.log("merge result:")
|
|
self.log("".join(ml))
|
|
self.assertEquals(ml, MERGED_RESULT)
|
|
|
|
def test_binary(self):
|
|
with self.assertRaises(error.Abort):
|
|
Merge3(["\x00"], ["a"], ["b"])
|
|
|
|
def test_dos_text(self):
|
|
base_text = "a\r\n"
|
|
this_text = "b\r\n"
|
|
other_text = "c\r\n"
|
|
m3 = Merge3(
|
|
base_text.splitlines(True),
|
|
other_text.splitlines(True),
|
|
this_text.splitlines(True),
|
|
)
|
|
m_lines = m3.merge_lines("OTHER", "THIS")
|
|
self.assertEqual(
|
|
"<<<<<<< OTHER\r\nc\r\n=======\r\nb\r\n"
|
|
">>>>>>> THIS\r\n".splitlines(True),
|
|
list(m_lines),
|
|
)
|
|
|
|
def test_mac_text(self):
|
|
base_text = "a\r"
|
|
this_text = "b\r"
|
|
other_text = "c\r"
|
|
m3 = Merge3(
|
|
base_text.splitlines(True),
|
|
other_text.splitlines(True),
|
|
this_text.splitlines(True),
|
|
)
|
|
m_lines = m3.merge_lines("OTHER", "THIS")
|
|
self.assertEqual(
|
|
"<<<<<<< OTHER\rc\r=======\rb\r" ">>>>>>> THIS\r".splitlines(True),
|
|
list(m_lines),
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# hide the timer
|
|
import time
|
|
|
|
orig = time.time
|
|
try:
|
|
time.time = lambda: 0
|
|
unittest.main()
|
|
finally:
|
|
time.time = orig
|