Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

_diff_text: use repr with escape characters #204

Merged
merged 3 commits into from
Feb 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions src/_pytest/assertion/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,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 @@ -226,10 +227,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 @@ -1042,7 +1048,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 @@ -1060,9 +1066,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 @@ -1073,12 +1086,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 @@ -1088,7 +1101,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 @@ -1137,6 +1150,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 @@ -1395,9 +1445,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