From 5fec793bc7d0e70b8e7a2a5ff384d254204fff05 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 2 Apr 2019 17:21:14 +0200 Subject: [PATCH 1/4] _compare_eq_sequence: display number of extra items --- src/_pytest/assertion/util.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index ab01c314c..231dd040d 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -285,19 +285,22 @@ def _compare_eq_iterable(left, right, verbose=0): def _compare_eq_sequence(left, right, verbose=0): explanation = [] - for i in range(min(len(left), len(right))): + len_left = len(left) + len_right = len(right) + for i in range(min(len_left, len_right)): if left[i] != right[i]: explanation += [u"At index %s diff: %r != %r" % (i, left[i], right[i])] break - if len(left) > len(right): + len_diff = len_left - len_right + if len_diff > 0: explanation += [ - u"Left contains more items, first extra item: %s" - % saferepr(left[len(right)]) + u"Left contains %d more items, first extra item: %s" + % (len_diff, saferepr(left[len_right])) ] - elif len(left) < len(right): + elif len_diff < 0: explanation += [ - u"Right contains more items, first extra item: %s" - % saferepr(right[len(left)]) + u"Right contains %d more items, first extra item: %s" + % (0 - len_diff, saferepr(right[len_left])) ] return explanation From 7f1bf44aa83c4d7d67d5f14fadd2e147e913ed99 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 2 Apr 2019 17:25:14 +0200 Subject: [PATCH 2/4] _compare_eq_dict: display number of different items --- src/_pytest/assertion/util.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index 231dd040d..08507a924 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -322,7 +322,9 @@ def _compare_eq_set(left, right, verbose=0): def _compare_eq_dict(left, right, verbose=0): explanation = [] - common = set(left).intersection(set(right)) + set_left = set(left) + set_right = set(right) + common = set_left.intersection(set_right) same = {k: left[k] for k in common if left[k] == right[k]} if same and verbose < 2: explanation += [u"Omitting %s identical items, use -vv to show" % len(same)] @@ -334,15 +336,15 @@ def _compare_eq_dict(left, right, verbose=0): explanation += [u"Differing items:"] for k in diff: explanation += [saferepr({k: left[k]}) + " != " + saferepr({k: right[k]})] - extra_left = set(left) - set(right) + extra_left = set_left - set_right if extra_left: - explanation.append(u"Left contains more items:") + explanation.append(u"Left contains %d more items:" % len(extra_left)) explanation.extend( pprint.pformat({k: left[k] for k in extra_left}).splitlines() ) - extra_right = set(right) - set(left) + extra_right = set_right - set_left if extra_right: - explanation.append(u"Right contains more items:") + explanation.append(u"Right contains %d more items:" % len(extra_right)) explanation.extend( pprint.pformat({k: right[k] for k in extra_right}).splitlines() ) From 47d92a0d96e9643402f7d22a73a797ebcde4403e Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 4 Apr 2019 17:53:39 +0200 Subject: [PATCH 3/4] Add tests and improve messages --- src/_pytest/assertion/util.py | 43 +++++++++++++++++++++++----------- testing/test_assertion.py | 44 +++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 14 deletions(-) diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index 08507a924..a62297075 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -292,16 +292,23 @@ def _compare_eq_sequence(left, right, verbose=0): explanation += [u"At index %s diff: %r != %r" % (i, left[i], right[i])] break len_diff = len_left - len_right - if len_diff > 0: - explanation += [ - u"Left contains %d more items, first extra item: %s" - % (len_diff, saferepr(left[len_right])) - ] - elif len_diff < 0: - explanation += [ - u"Right contains %d more items, first extra item: %s" - % (0 - len_diff, saferepr(right[len_left])) - ] + + if len_diff: + if len_diff > 0: + dir_with_more = "Left" + extra = saferepr(left[len_right]) + elif len_diff < 0: + len_diff = 0 - len_diff + dir_with_more = "Right" + extra = saferepr(right[len_left]) + + if len_diff == 1: + explanation += [u"%s contains one more item: %s" % (dir_with_more, extra)] + else: + explanation += [ + u"%s contains %d more items, first extra item: %s" + % (dir_with_more, len_diff, extra) + ] return explanation @@ -337,14 +344,22 @@ def _compare_eq_dict(left, right, verbose=0): for k in diff: explanation += [saferepr({k: left[k]}) + " != " + saferepr({k: right[k]})] extra_left = set_left - set_right - if extra_left: - explanation.append(u"Left contains %d more items:" % len(extra_left)) + len_extra_left = len(extra_left) + if len_extra_left: + explanation.append( + u"Left contains %d more item%s:" + % (len_extra_left, "" if len_extra_left == 1 else "s") + ) explanation.extend( pprint.pformat({k: left[k] for k in extra_left}).splitlines() ) extra_right = set_right - set_left - if extra_right: - explanation.append(u"Right contains %d more items:" % len(extra_right)) + len_extra_right = len(extra_right) + if len_extra_right: + explanation.append( + u"Right contains %d more item%s:" + % (len_extra_right, "" if len_extra_right == 1 else "s") + ) explanation.extend( pprint.pformat({k: right[k] for k in extra_right}).splitlines() ) diff --git a/testing/test_assertion.py b/testing/test_assertion.py index 330b711af..8a59b7e8d 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -446,6 +446,50 @@ class TestAssert_reprcompare(object): assert "Omitting" not in lines[1] assert lines[2] == "{'b': 1}" + def test_dict_different_items(self): + lines = callequal({"a": 0}, {"b": 1, "c": 2}, verbose=2) + assert lines == [ + "{'a': 0} == {'b': 1, 'c': 2}", + "Left contains 1 more item:", + "{'a': 0}", + "Right contains 2 more items:", + "{'b': 1, 'c': 2}", + "Full diff:", + "- {'a': 0}", + "+ {'b': 1, 'c': 2}", + ] + lines = callequal({"b": 1, "c": 2}, {"a": 0}, verbose=2) + assert lines == [ + "{'b': 1, 'c': 2} == {'a': 0}", + "Left contains 2 more items:", + "{'b': 1, 'c': 2}", + "Right contains 1 more item:", + "{'a': 0}", + "Full diff:", + "- {'b': 1, 'c': 2}", + "+ {'a': 0}", + ] + + def test_sequence_different_items(self): + lines = callequal((1, 2), (3, 4, 5), verbose=2) + assert lines == [ + "(1, 2) == (3, 4, 5)", + "At index 0 diff: 1 != 3", + "Right contains one more item: 5", + "Full diff:", + "- (1, 2)", + "+ (3, 4, 5)", + ] + lines = callequal((1, 2, 3), (4,), verbose=2) + assert lines == [ + "(1, 2, 3) == (4,)", + "At index 0 diff: 1 != 4", + "Left contains 2 more items, first extra item: 2", + "Full diff:", + "- (1, 2, 3)", + "+ (4,)", + ] + def test_set(self): expl = callequal({0, 1}, {0, 2}) assert len(expl) > 1 From 0f965e57a23313b0020e1c9737380dbe18b6d088 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 5 Apr 2019 12:12:29 +0200 Subject: [PATCH 4/4] changelog, fix branch coverage --- changelog/5026.feature.rst | 1 + src/_pytest/assertion/util.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelog/5026.feature.rst diff --git a/changelog/5026.feature.rst b/changelog/5026.feature.rst new file mode 100644 index 000000000..aa0f3cbb3 --- /dev/null +++ b/changelog/5026.feature.rst @@ -0,0 +1 @@ +Assertion failure messages for sequences and dicts contain the number of different items now. diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py index a62297075..b53646859 100644 --- a/src/_pytest/assertion/util.py +++ b/src/_pytest/assertion/util.py @@ -297,7 +297,7 @@ def _compare_eq_sequence(left, right, verbose=0): if len_diff > 0: dir_with_more = "Left" extra = saferepr(left[len_right]) - elif len_diff < 0: + else: len_diff = 0 - len_diff dir_with_more = "Right" extra = saferepr(right[len_left])