Skip to content

Commit

Permalink
_diff_text: use repr with escape characters (#204)
Browse files Browse the repository at this point in the history
  • Loading branch information
blueyed authored Feb 13, 2020
1 parent 188bab7 commit 642d74f
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 17 deletions.
17 changes: 13 additions & 4 deletions src/_pytest/assertion/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ def _diff_text(left: str, right: str, verbose: int = 0) -> List[str]:
characters which are identical to keep the diff minimal.
"""
from difflib import ndiff
from wcwidth import wcswidth

explanation = [] # type: List[str]

Expand Down Expand Up @@ -227,10 +228,18 @@ def _diff_text(left: str, right: str, verbose: int = 0) -> List[str]:
left = repr(str(left))
right = repr(str(right))
explanation += ["Strings contain only whitespace, escaping them using repr()"]
explanation += [
line.strip("\n")
for line in ndiff(left.splitlines(keepends), right.splitlines(keepends))
]

left_lines = left.splitlines(keepends)
right_lines = right.splitlines(keepends)

if any(wcswidth(x) == -1 for x in left_lines + right_lines):
left_lines = [repr(x) for x in left_lines]
right_lines = [repr(x) for x in right_lines]
explanation += [
"Strings contain non-printable/escape characters, escaping them using repr()"
]

explanation += [line.strip("\n") for line in ndiff(left_lines, right_lines)]
return explanation


Expand Down
77 changes: 64 additions & 13 deletions testing/test_assertion.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,8 +345,14 @@ def test_multiline_text_diff(self):
left = "foo\nspam\nbar"
right = "foo\neggs\nbar"
diff = callequal(left, right)
assert "- spam" in diff
assert "+ eggs" in diff
assert diff == [
"'foo\\nspam\\nbar' == 'foo\\neggs\\nbar'",
"Strings contain non-printable/escape characters, escaping them using repr()",
" 'foo\\n'",
"- 'spam\\n'",
"+ 'eggs\\n'",
" 'bar'",
]

def test_bytes_diff_normal(self):
"""Check special handling for bytes diff (#5260)"""
Expand Down Expand Up @@ -1070,7 +1076,7 @@ def test_full_output_truncated(self, monkeypatch, testdir):

line_count = 7
line_len = 100
expected_truncated_lines = 2
expected_truncated_lines = 3
testdir.makepyfile(
r"""
def test_many_lines():
Expand All @@ -1088,9 +1094,16 @@ def test_many_lines():
# without -vv, truncate the message showing a few diff lines only
result.stdout.fnmatch_lines(
[
"*- 1*",
"*- 3*",
"*- 5*",
"> assert a == b",
"E AssertionError: assert '000000000000...6666666666666' == '000000000000...6666666666666'",
"E Skipping 91 identical leading characters in diff, use -v to show",
"E Strings contain non-printable/escape characters, escaping them using repr()",
"E '000000000\\n'",
"E - '1*\\n'",
"E '2*\\n'",
"E - '3*\\n'",
"E '4*\\...",
"E ",
"*truncated (%d lines hidden)*use*-vv*" % expected_truncated_lines,
]
)
Expand All @@ -1101,12 +1114,12 @@ def test_many_lines():
["*truncated (%d lines hidden)*use*-vv*" % expected_truncated_lines]
)
result = testdir.runpytest("-o", "assert_truncate_level=0")
result.stdout.fnmatch_lines(["* 6*"])
result.stdout.fnmatch_lines(["* '6*"])
result = testdir.runpytest("-v", "-o", "assert_truncate_level=0")
result.stdout.fnmatch_lines(["* 6*"])
result.stdout.fnmatch_lines(["* '6*"])

result = testdir.runpytest("-vv")
result.stdout.fnmatch_lines(["* 6*"])
result.stdout.fnmatch_lines(["* '6*"])

monkeypatch.setenv("CI", "")
result = testdir.runpytest()
Expand All @@ -1116,7 +1129,7 @@ def test_many_lines():

monkeypatch.setenv("CI", "True")
result = testdir.runpytest()
result.stdout.fnmatch_lines(["* 6*"])
result.stdout.fnmatch_lines(["* '6*"])


def test_python25_compile_issue257(testdir):
Expand Down Expand Up @@ -1165,6 +1178,43 @@ def test_reprcompare_whitespaces():
]


def test_reprcompare_escape_sequences():
config = mock_config()
detail = plugin.pytest_assertrepr_compare(
config, "==", "\x1b[31mred", "\x1b[31mgreen"
)
assert detail == [
"'\\x1b[31mred' == '\\x1b[31mgreen'",
"Strings contain non-printable/escape characters, escaping them using repr()",
"- '\\x1b[31mred'",
"? ^",
"+ '\\x1b[31mgreen'",
"? + ^^",
]

detail = plugin.pytest_assertrepr_compare(
config, "==", ["\x1b[31mred"], ["\x1b[31mgreen"]
)
assert detail == [
"['\\x1b[31mred'] == ['\\x1b[31mgreen']",
"At index 0 diff: '\\x1b[31mred' != '\\x1b[31mgreen'",
"Use -v to get the full diff",
]
config = mock_config(verbose=2)
detail = plugin.pytest_assertrepr_compare(
config, "==", ["\x1b[31mred"], ["\x1b[31mgreen"]
)
assert detail == [
"['\\x1b[31mred'] == ['\\x1b[31mgreen']",
"At index 0 diff: '\\x1b[31mred' != '\\x1b[31mgreen'",
"Full diff:",
"- ['\\x1b[31mred']",
"? ^",
"+ ['\\x1b[31mgreen']",
"? + ^^",
]


def test_pytest_assertrepr_compare_integration(testdir):
testdir.makepyfile(
"""
Expand Down Expand Up @@ -1423,9 +1473,10 @@ def test_diff():
result.stdout.fnmatch_lines(
r"""
*assert 'asdf' == 'asdf\n'
* - asdf
* + asdf
* ? +
E Strings contain non-printable/escape characters, escaping them using repr()
* - 'asdf'
* + 'asdf\n'
* ? ++
"""
)

Expand Down

0 comments on commit 642d74f

Please sign in to comment.