Skip to content

Commit 3b26fdd

Browse files
[test] Cover the streaming truncation coverage gaps
Close the patch-coverage gaps codecov flagged on the streaming refactor: * a plugin returning a truthy-but-empty iterator (``iter([])``), which slips past the first falsy check but is empty once materialised through truncation — exercises the second skip in ``callbinrepr``. * a ``--assert=plain`` run, exercising the false branch of the ``assertmode == "rewrite"`` guard. * every hook returning ``None`` (``assert 1 == 2``), so the dispatcher falls through the loop and returns ``None``. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent d477299 commit 3b26fdd

1 file changed

Lines changed: 71 additions & 2 deletions

File tree

testing/test_assertion.py

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2291,8 +2291,7 @@ def raise_exit(obj):
22912291
def test_plugin_hook_returning_none_is_skipped(pytester: Pytester) -> None:
22922292
"""A ``pytest_assertrepr_compare`` impl returning ``None`` is skipped
22932293
so the next impl (or the built-in) can produce the explanation.
2294-
Covers the ``if new_expl is None: continue`` branch in
2295-
``callbinrepr``.
2294+
Covers the ``if not new_expl: continue`` branch in ``callbinrepr``.
22962295
"""
22972296
pytester.makeconftest(
22982297
"""
@@ -2315,6 +2314,76 @@ def test_diff():
23152314
)
23162315

23172316

2317+
def test_plugin_hook_returning_empty_iterator_is_skipped(pytester: Pytester) -> None:
2318+
"""A plugin returning a truthy but ultimately empty iterable is
2319+
skipped after materialisation. Covers the second
2320+
``if not new_expl: continue`` branch in ``callbinrepr``.
2321+
"""
2322+
pytester.makeconftest(
2323+
"""
2324+
def pytest_assertrepr_compare(op, left, right):
2325+
# An iterator object is truthy, so it slips past the first
2326+
# falsy check; once materialised through truncation it is
2327+
# empty and the dispatcher must move on.
2328+
return iter([])
2329+
"""
2330+
)
2331+
pytester.makepyfile(
2332+
"""
2333+
def test_diff():
2334+
assert {1, 2} == {1, 3}
2335+
"""
2336+
)
2337+
result = pytester.runpytest()
2338+
# The built-in set-comparison explanation still reaches the user.
2339+
result.stdout.fnmatch_lines(
2340+
["*Extra items in the left set:*", "*Extra items in the right set:*"]
2341+
)
2342+
2343+
2344+
def test_callbinrepr_falls_through_when_all_hooks_return_none(
2345+
pytester: Pytester,
2346+
) -> None:
2347+
"""When every ``pytest_assertrepr_compare`` impl returns ``None``
2348+
(no specialised explanation applies, e.g. ``assert 1 == 2``), the
2349+
dispatcher exhausts ``hook_result``, exits the loop, and returns
2350+
``None``. Covers the ``continue → loop exit`` branch on the first
2351+
``if not new_expl: continue`` line.
2352+
"""
2353+
pytester.makepyfile(
2354+
"""
2355+
def test_trivial():
2356+
assert 1 == 2
2357+
"""
2358+
)
2359+
result = pytester.runpytest()
2360+
# Just the plain ``assert 1 == 2`` rewrite, with no specialised
2361+
# comparator explanation appended (because the dispatcher fell
2362+
# through to ``return None``).
2363+
result.stdout.fnmatch_lines(["*assert 1 == 2*"])
2364+
result.assert_outcomes(failed=1)
2365+
2366+
2367+
def test_callbinrepr_plain_assert_mode(pytester: Pytester) -> None:
2368+
"""In ``--assert=plain`` mode ``callbinrepr`` skips the ``%`` escape.
2369+
Covers the false branch of ``if item.config.getvalue("assertmode")
2370+
== "rewrite"``.
2371+
"""
2372+
pytester.makepyfile(
2373+
"""
2374+
def test_diff():
2375+
assert {1, 2} == {1, 3}
2376+
"""
2377+
)
2378+
result = pytester.runpytest("--assert=plain")
2379+
# In plain mode the comparator still runs via ``callbinrepr`` (it
2380+
# is the rewrite escaping that's skipped), so the explanation is
2381+
# still produced.
2382+
result.stdout.fnmatch_lines(
2383+
["*Extra items in the left set:*", "*Extra items in the right set:*"]
2384+
)
2385+
2386+
23182387
def test_exception_before_first_yield_emits_summary_and_notice(monkeypatch) -> None:
23192388
"""When the comparator raises *before* any explanation line has been
23202389
yielded, ``assertrepr_compare`` should still produce the summary so

0 commit comments

Comments
 (0)