diff --git a/changelog/13652.bugfix.rst b/changelog/13652.bugfix.rst new file mode 100644 index 00000000000..12ff991a796 --- /dev/null +++ b/changelog/13652.bugfix.rst @@ -0,0 +1 @@ +``contains one more item`` now reports the actual extra item in sequence diffs. diff --git a/src/_pytest/assertion/_compare_sequence.py b/src/_pytest/assertion/_compare_sequence.py index cada856cc85..3514d9d2300 100644 --- a/src/_pytest/assertion/_compare_sequence.py +++ b/src/_pytest/assertion/_compare_sequence.py @@ -52,6 +52,8 @@ def _compare_eq_sequence( comparing_bytes = isinstance(left, bytes) and isinstance(right, bytes) len_left = len(left) len_right = len(right) + found_diff = False + i = -1 for i in range(min(len_left, len_right)): if left[i] != right[i]: if comparing_bytes: @@ -73,6 +75,7 @@ def _compare_eq_sequence( f"At index {i} diff:" f" {highlighter(repr(left_value))} != {highlighter(repr(right_value))}" ) + found_diff = True break if comparing_bytes: @@ -84,11 +87,17 @@ def _compare_eq_sequence( if len_diff: if len_diff > 0: dir_with_more = "Left" - extra = saferepr(left[len_right]) + if found_diff and len_diff == 1: + extra = saferepr(left[i]) + else: + extra = saferepr(left[len_right]) else: len_diff = 0 - len_diff dir_with_more = "Right" - extra = saferepr(right[len_left]) + if found_diff and len_diff == 1: + extra = saferepr(right[i]) + else: + extra = saferepr(right[len_left]) if len_diff == 1: yield f"{dir_with_more} contains one more item: {highlighter(extra)}" diff --git a/testing/test_assertion.py b/testing/test_assertion.py index 035aad31c54..e61483f9665 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -1122,7 +1122,7 @@ def test_sequence_different_items(self) -> None: "(1, 2) == (3, 4, 5)", "", "At index 0 diff: 1 != 3", - "Right contains one more item: 5", + "Right contains one more item: 3", "", "Full diff: (-: missing in left side, +: extra in left side)", " (", @@ -1170,6 +1170,28 @@ def test_sequence_different_items(self) -> None: " )", ] + @pytest.mark.parametrize( + ("left", "right", "expected"), + [ + ([], [1], "Right contains one more item: 1"), + ([1], [], "Left contains one more item: 1"), + ([1, 2, 3], [1, 2, 3, 4], "Right contains one more item: 4"), + ([1, 2, 3], [1, 2, 0, 3], "Right contains one more item: 0"), + ([1, 2, 0, 3], [1, 2, 3], "Left contains one more item: 0"), + ( + [1, 2, 3], + [0, 1, 2, 3, 4], + "Right contains 2 more items, first extra item: 3", + ), + ], + ) + def test_sequence_extra_item_message( + self, left: list[object], right: list[object], expected: str + ) -> None: + lines = callequal(left, right, verbose=1) + assert lines is not None + assert expected in lines + def test_set(self) -> None: expl = callequal({0, 1}, {0, 2}) assert expl is not None diff --git a/testing/test_error_diffs.py b/testing/test_error_diffs.py index 653559c8a99..34e900d6ea7 100644 --- a/testing/test_error_diffs.py +++ b/testing/test_error_diffs.py @@ -66,7 +66,7 @@ def test_this(): > assert result == expected E assert [1, 3] == [1, 2, 3] E At index 1 diff: 3 != 2 - E Right contains one more item: 3 + E Right contains one more item: 2 E Full diff: (-: missing in left side, +: extra in left side) E [ E 1, @@ -76,6 +76,28 @@ def test_this(): """, id="Compare lists, one item missing", ), + pytest.param( + """ + def test_this(): + result = [1, 2, 3] + expected = [1, 2, 0, 3] + assert result == expected + """, + """ + > assert result == expected + E assert [1, 2, 3] == [1, 2, 0, 3] + E At index 2 diff: 3 != 0 + E Right contains one more item: 0 + E Full diff: (-: missing in left side, +: extra in left side) + E [ + E 1, + E 2, + E - 0, + E 3, + E ] + """, + id="Compare lists, one extra item inserted mid-list", + ), pytest.param( """ def test_this():