Commit 4cbca968 authored by Ximin Luo's avatar Ximin Luo

tests: add a test case for #875281

parent 98de493b
......@@ -252,6 +252,13 @@ def diff(feeder1, feeder2):
return run_diff(fifo1_path, fifo2_path, fifo1.end_nl_q, fifo2.end_nl_q)
def diff_split_lines(diff, keepends=True):
lines = diff.split("\n")
if not keepends:
return lines
return [line + "\n" for line in lines[:-1]] + ([lines[-1]] if lines[-1] else [])
def reverse_unified_diff(diff):
res = []
for line in diff.splitlines(keepends=True):
......@@ -22,7 +22,7 @@ import logging
from . import feeders
from .exc import RequiredToolNotFound
from .diff import diff, reverse_unified_diff
from .diff import diff, reverse_unified_diff, diff_split_lines
from .excludes import command_excluded
logger = logging.getLogger(__name__)
......@@ -70,27 +70,45 @@ class Difference(object):
def get_reverse(self):
logger.debug("Reverse orig %s %s", self.source1, self.source2)
def map_lines(self, f_diff, f_comment):
unified_diff = self.unified_diff
return self.__class__(
"".join(map(f_diff, diff_split_lines(unified_diff))) if unified_diff is not None else None,
comment=["".join(map(f_comment, diff_split_lines(comment))) for comment in self.comments],
def fmap(self, f):
if self._visuals:
raise NotImplementedError(
"Reversing VisualDifference is not yet implemented",
"fmap on VisualDifference is not yet implemented",
return f(self.__class__(
details=[d.fmap(f) for d in self._details],
diff = self.unified_diff
if diff is not None:
diff = reverse_unified_diff(self.unified_diff)
return Difference(
def _reverse_self(self):
return self.__class__(
reverse_unified_diff(self.unified_diff) if self.unified_diff is not None else None,
details=[d.get_reverse() for d in self._details],
def get_reverse(self):
logger.debug("Reverse orig %s %s", self.source1, self.source2)
return self.fmap(Difference._reverse_self)
def equals(self, other):
return self == other or (
self.unified_diff == other.unified_diff and
......@@ -28,4 +28,4 @@ def load_diff_from_path(path):
def load_diff(fp, path):
return JSONReaderV1().load(fp, 'stdin')
return JSONReaderV1().load(fp, path)
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -17,14 +17,18 @@
# You should have received a copy of the GNU General Public License
# along with diffoscope. If not, see <>.
import io
import os
import re
import pytest
from diffoscope.main import main
from diffoscope.readers import load_diff_from_path
from diffoscope.presenters.utils import create_limited_print_func, PrintLimitReached, PartialString
from diffoscope.presenters.json import JSONPresenter
from import cwd_data, get_data
from .utils import diff_expand
from import cwd_data, data, get_data
from import skip_unless_tools_exist
re_html = re.compile(r'.*<body(?P<body>.*)<div class="footer">', re.MULTILINE | re.DOTALL)
......@@ -58,6 +62,14 @@ def extract_body(val):
return result
def expand_collapsed_json(tmpdir, name):
diff = load_diff_from_path(data(name + ".collapsed-diff.json"))
diff_path = str(tmpdir.join(name + '.diff.json'))
with open(diff_path, 'w') as fp:
JSONPresenter(lambda x: print(x, file=fp)).start(diff.fmap(diff_expand))
return diff_path
def test_text_option_is_default(capsys):
out = run(capsys)
......@@ -158,6 +170,14 @@ def test_html_option_with_stdout(capsys):
assert body.count('div class="difference"') == 4
def test_html_regression_875281(tmpdir, capsys):
# this test fails when you `git revert -Xtheirs ccd926f`
diff_path = expand_collapsed_json(tmpdir, 'debian-bug-875281')
report_path = str(tmpdir.join('report.html'))
out = run(capsys, '--html', report_path, pair=(diff_path,))
assert out == ''
def test_limited_print():
def fake(x): return None
with pytest.raises(PrintLimitReached):
......@@ -17,6 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with diffoscope. If not, see <>.
import html
import re
re_diff_line_numbers = re.compile(r"(^|\n)@@ -(\d+),(\d+) \+(\d+),(\d+) @@(?=\n|$)")
......@@ -24,3 +25,22 @@ re_diff_line_numbers = re.compile(r"(^|\n)@@ -(\d+),(\d+) \+(\d+),(\d+) @@(?=\n|
def diff_ignore_line_numbers(diff):
return re_diff_line_numbers.sub(r"\1@@ -XX,XX +XX,XX @@", diff)
def _collapse_line(line, escape=html.escape):
l = len(escape(line))
return str(l - 1) + "\n" if line[-1] == "\n" else str(l)
def _diff_collapse_line(line):
return line[0] + _collapse_line(line[1:]) if line and line[0] in '+- ' else line
def _expand_line(line):
return (int(line[:-1]) * ".") + "\n" if line[-1] == "\n" else (int(line) * ".")
def _diff_expand_line(line):
return line[0] + _expand_line(line[1:]) if line and line[0] in '+- ' else line
def diff_collapse(diff):
return diff.map_lines(_diff_collapse_line, _collapse_line)
def diff_expand(diff):
return diff.map_lines(_diff_expand_line, _expand_line)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment