Skip to content

Commit ac76b86

Browse files
authored
Merge pull request #16 from hjwp/long-lines
handle edge case of short diffs containing long elements better
2 parents 73f7b60 + b39cc23 commit ac76b86

File tree

2 files changed

+84
-18
lines changed

2 files changed

+84
-18
lines changed

pytest_icdiff.py

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1+
# pylint: disable=inconsistent-return-statements
2+
import py
13
from pprintpp import pformat
24
import icdiff
35

6+
COLS = py.io.TerminalWriter().fullwidth # pylint: disable=no-member
7+
MARGIN_L = 9
8+
GUTTER = 2
9+
MARGINS = MARGIN_L + GUTTER + 1
10+
411

512
def pytest_assertrepr_compare(config, op, left, right):
613
if op != '==':
@@ -12,25 +19,23 @@ def pytest_assertrepr_compare(config, op, left, right):
1219
except TypeError:
1320
pass
1421

15-
terminal_writer = config.get_terminal_writer()
16-
cols = terminal_writer.fullwidth - 12
17-
18-
wide_left = pformat(left, indent=2, width=cols / 2).splitlines()
19-
wide_right = pformat(right, indent=2, width=cols / 2).splitlines()
20-
if len(wide_left) < 3 or len(wide_right) < 3:
21-
shortest_left = pformat(left, indent=2, width=1).splitlines()
22-
shortest_right = pformat(right, indent=2, width=1).splitlines()
23-
cols = max(len(l) for l in shortest_left + shortest_right) * 2
24-
else:
25-
cols = max(len(l) for l in wide_left + wide_right) * 2
22+
half_cols = COLS / 2 - MARGINS
2623

27-
pretty_left = pformat(left, indent=2, width=cols / 2).splitlines()
28-
pretty_right = pformat(right, indent=2, width=cols / 2).splitlines()
24+
pretty_left = pformat(left, indent=2, width=half_cols).splitlines()
25+
pretty_right = pformat(right, indent=2, width=half_cols).splitlines()
26+
diff_cols = COLS - MARGINS
2927

28+
if len(pretty_left) < 3 or len(pretty_right) < 3:
29+
# avoid small diffs far apart by smooshing them up to the left
30+
pretty_left = pformat(left, indent=2, width=1).splitlines()
31+
pretty_right = pformat(right, indent=2, width=1).splitlines()
32+
diff_cols = max(len(l) + 1 for l in pretty_left + pretty_right) * 2
33+
if (diff_cols + MARGINS) > COLS:
34+
diff_cols = COLS - MARGINS
3035

31-
differ = icdiff.ConsoleDiff(cols=cols + 12, tabsize=2)
36+
differ = icdiff.ConsoleDiff(cols=diff_cols, tabsize=2)
3237

33-
if not terminal_writer.hasmarkup:
38+
if not config.get_terminal_writer().hasmarkup:
3439
# colorization is disabled in Pytest - either due to the terminal not
3540
# supporting it or the user disabling it. We should obey, but there is
3641
# no option in icdiff to disable it, so we replace its colorization

tests/test_pytest_icdiff.py

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def test_one():
2424
assert {one!r} == {two!r}
2525
"""
2626
)
27-
output = testdir.runpytest().stdout.str()
27+
output = testdir.runpytest('-vv').stdout.str()
2828
print(repr(output))
2929
two_left = "'the number two'"
3030
two_right = "'the number three'"
@@ -52,7 +52,7 @@ def test_one():
5252
)
5353
# Force colorization in py TerminalWriter
5454
testdir.monkeypatch.setenv('PY_COLORS', '1')
55-
output = testdir.runpytest().stdout.str()
55+
output = testdir.runpytest('-vv').stdout.str()
5656
print(repr(output))
5757
two_left = f"'the number t{YELLOW_ON}wo{COLOR_OFF}'"
5858
two_right = f"'the number t{YELLOW_ON}hree{COLOR_OFF}'"
@@ -173,7 +173,7 @@ def test_one():
173173
assert {one!r} == {two!r}
174174
"""
175175
)
176-
output = testdir.runpytest().stdout.str()
176+
output = testdir.runpytest('-vv').stdout.str()
177177
print(repr(output))
178178
assert re.search(r"1: '1',\s+$", output, flags=re.MULTILINE)
179179

@@ -188,3 +188,64 @@ def test_a():
188188
output = testdir.runpytest().stdout.str()
189189
drilldown_expression = 'where 3 = len([1, 2, 3])'
190190
assert drilldown_expression in output
191+
192+
193+
def test_long_lines_in_comparators_are_wrapped_sensibly_multiline(testdir):
194+
left = {1: "hello " * 20, 2: 'two'}
195+
right = {1: "hella " * 20, 2: 'two'}
196+
testdir.makepyfile(
197+
f"""
198+
def test_one():
199+
assert {left!r} == {right!r}
200+
"""
201+
)
202+
output = testdir.runpytest('-vv', '--color=yes').stdout.str()
203+
comparison_line = next(l for l in output.splitlines() if '1:' in l and "assert" not in l)
204+
assert comparison_line.count('hell') < 13
205+
206+
def test_long_lines_in_comparators_are_wrapped_sensibly_singleline(testdir):
207+
left = "hello " * 10
208+
right = "hella " * 10
209+
testdir.makepyfile(
210+
f"""
211+
def test_one():
212+
assert {left!r} == {right!r}
213+
"""
214+
)
215+
output = testdir.runpytest('-vv', '--color=yes').stdout.str()
216+
comparison_line = next(
217+
l for l in output.splitlines()
218+
if "hell" in l and "assert" not in l
219+
)
220+
assert comparison_line.count('hell') < 15
221+
222+
223+
def test_columns_are_calculated_outside_hook(testdir):
224+
"""
225+
ok for some reason if you get the TerminalWriter width
226+
inside of the hook it just always returns 80.
227+
but (bear with me here) if you monkeypatch.setenv(COLUMNS)
228+
then it _does_ affect the width inside the hook
229+
(which is where we don't want to measure it)
230+
but it does _not_ affect the one outside the hook
231+
(which is the one we want to use).
232+
"""
233+
left = "hello " * 10
234+
right = "hella " * 10
235+
testdir.makepyfile(
236+
f"""
237+
def test_one():
238+
assert {left!r} == {right!r}
239+
"""
240+
)
241+
testdir.monkeypatch.setenv('COLUMNS', '50')
242+
# testdir._method = 'subprocess'
243+
output = testdir.runpytest(
244+
'-vv', '--color=yes',
245+
).stdout.str()
246+
comparison_line = next(
247+
l for l in output.splitlines()
248+
if 'hell' in l and "assert" not in l
249+
)
250+
assert comparison_line.count('hell') > 5
251+

0 commit comments

Comments
 (0)