From 8c7eb8236348c8fb8db43a6a9c02ba442a09f6b8 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Wed, 15 May 2019 12:03:00 +0200 Subject: [PATCH 1/2] Fix/improve comparison of byte strings Fixes https://github.com/pytest-dev/pytest/issues/5260. --- changelog/5260.bugfix.rst | 1 + src/_pytest/assertion/util.py | 5 ++++- testing/test_assertion.py | 12 ++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 changelog/5260.bugfix.rst diff --git a/changelog/5260.bugfix.rst b/changelog/5260.bugfix.rst new file mode 100644 index 000000000..ab521d163 --- /dev/null +++ b/changelog/5260.bugfix.rst @@ -0,0 +1 @@ +Improve/fix comparison of byte strings with Python 3. diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index 762e5761d..493c630f6 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -263,8 +263,11 @@ def _compare_eq_sequence(left, right, verbose=0): "At index {} diff: {!r} != {!r}".format(i, left[i], right[i]) ] break - len_diff = len_left - len_right + if isinstance(left, bytes): + return explanation + + len_diff = len_left - len_right if len_diff: if len_diff > 0: dir_with_more = "Left" diff --git a/testing/test_assertion.py b/testing/test_assertion.py index 0fcfd9f27..f9c67d703 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -331,6 +331,18 @@ class TestAssert_reprcompare: assert "- spam" in diff assert "+ eggs" in diff + def test_bytes_diff(self): + diff = callequal(b"spam", b"eggs") + if PY3: + assert diff == [ + "b'spam' == b'eggs'", + "At index 0 diff: 115 != 101", + "Use -v to get the full diff", + ] + else: + # Handled as text on Python 2. + assert diff == ["'spam' == 'eggs'", "- spam", "+ eggs"] + def test_list(self): expl = callequal([0, 1], [0, 2]) assert len(expl) > 1 From 3f2344e8f73784b40df28d82a44249827206dc63 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Tue, 25 Jun 2019 20:30:18 -0300 Subject: [PATCH 2/2] Show bytes ascii representation instead of numeric value --- changelog/5260.bugfix.rst | 18 +++++++++++++++++- src/_pytest/assertion/util.py | 22 ++++++++++++++++++++-- testing/test_assertion.py | 29 +++++++++++++++++++---------- 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/changelog/5260.bugfix.rst b/changelog/5260.bugfix.rst index ab521d163..484c1438a 100644 --- a/changelog/5260.bugfix.rst +++ b/changelog/5260.bugfix.rst @@ -1 +1,17 @@ -Improve/fix comparison of byte strings with Python 3. +Improved comparison of byte strings. + +When comparing bytes, the assertion message used to show the byte numeric value when showing the differences:: + + def test(): + > assert b'spam' == b'eggs' + E AssertionError: assert b'spam' == b'eggs' + E At index 0 diff: 115 != 101 + E Use -v to get the full diff + +It now shows the actual ascii representation instead, which is often more useful:: + + def test(): + > assert b'spam' == b'eggs' + E AssertionError: assert b'spam' == b'eggs' + E At index 0 diff: b's' != b'e' + E Use -v to get the full diff diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index 493c630f6..b808cb509 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -254,17 +254,35 @@ def _compare_eq_iterable(left, right, verbose=0): def _compare_eq_sequence(left, right, verbose=0): + comparing_bytes = isinstance(left, bytes) and isinstance(right, bytes) explanation = [] len_left = len(left) len_right = len(right) for i in range(min(len_left, len_right)): if left[i] != right[i]: + if comparing_bytes: + # when comparing bytes, we want to see their ascii representation + # instead of their numeric values (#5260) + # using a slice gives us the ascii representation: + # >>> s = b'foo' + # >>> s[0] + # 102 + # >>> s[0:1] + # b'f' + left_value = left[i : i + 1] + right_value = right[i : i + 1] + else: + left_value = left[i] + right_value = right[i] + explanation += [ - "At index {} diff: {!r} != {!r}".format(i, left[i], right[i]) + "At index {} diff: {!r} != {!r}".format(i, left_value, right_value) ] break - if isinstance(left, bytes): + if comparing_bytes: + # when comparing bytes, it doesn't help to show the "sides contain one or more items" + # longer explanation, so skip it return explanation len_diff = len_left - len_right diff --git a/testing/test_assertion.py b/testing/test_assertion.py index f9c67d703..f58d240a5 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -331,17 +331,26 @@ class TestAssert_reprcompare: assert "- spam" in diff assert "+ eggs" in diff - def test_bytes_diff(self): + def test_bytes_diff_normal(self): + """Check special handling for bytes diff (#5260)""" diff = callequal(b"spam", b"eggs") - if PY3: - assert diff == [ - "b'spam' == b'eggs'", - "At index 0 diff: 115 != 101", - "Use -v to get the full diff", - ] - else: - # Handled as text on Python 2. - assert diff == ["'spam' == 'eggs'", "- spam", "+ eggs"] + + assert diff == [ + "b'spam' == b'eggs'", + "At index 0 diff: b's' != b'e'", + "Use -v to get the full diff", + ] + + def test_bytes_diff_verbose(self): + """Check special handling for bytes diff (#5260)""" + diff = callequal(b"spam", b"eggs", verbose=True) + assert diff == [ + "b'spam' == b'eggs'", + "At index 0 diff: b's' != b'e'", + "Full diff:", + "- b'spam'", + "+ b'eggs'", + ] def test_list(self): expl = callequal([0, 1], [0, 2])