From 2ace7a261901e164bf54606b80a2dd1b4e49a904 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 23 Nov 2024 14:19:20 -0500 Subject: [PATCH] fix: don't assume 'no branches' means 'not executed' #1896 --- CHANGES.rst | 7 ++++++- coverage/lcovreport.py | 4 +--- tests/test_lcov.py | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 4346d1d9d..3b1337d2d 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -23,7 +23,12 @@ upgrading your version of coverage.py. Unreleased ---------- -Nothing yet. +- fix: the LCOV report code assumed that a branch line that took no branches + meant that the entire line was unexecuted. This isn't true in a few cases: + the line might always raise an exception, or might have been optimized away. + Fixes `issue 1896`_. + +.. _issue 1896: https://github.com/nedbat/coveragepy/issues/1896 .. start-releases diff --git a/coverage/lcovreport.py b/coverage/lcovreport.py index 70507c003..c8512cdf8 100644 --- a/coverage/lcovreport.py +++ b/coverage/lcovreport.py @@ -118,10 +118,8 @@ def lcov_arcs( if taken == 0: # When _none_ of the out arcs from 'line' were executed, - # this probably means 'line' was never executed at all. - # Cross-check with the line stats. + # it can mean the line always raised an exception. assert len(executed_arcs[line]) == 0 - assert line in analysis.missing destinations = [ (dst, "-") for dst in missing_arcs[line] ] diff --git a/tests/test_lcov.py b/tests/test_lcov.py index e2c340f13..fe6016da2 100644 --- a/tests/test_lcov.py +++ b/tests/test_lcov.py @@ -526,3 +526,35 @@ def foo(a): """) actual_result = self.get_lcov_report_content() assert expected_result == actual_result + + def test_always_raise(self) -> None: + self.make_file("always_raise.py", """\ + try: + if not_defined: + print("Yes") + else: + print("No") + except Exception: + pass + """) + cov = coverage.Coverage(source=".", branch=True) + self.start_import_stop(cov, "always_raise") + cov.lcov_report() + expected_result = textwrap.dedent("""\ + SF:always_raise.py + DA:1,1 + DA:2,1 + DA:3,0 + DA:5,0 + DA:6,1 + DA:7,1 + LF:6 + LH:4 + BRDA:2,0,jump to line 3,- + BRDA:2,0,jump to line 5,- + BRF:2 + BRH:0 + end_of_record + """) + actual_result = self.get_lcov_report_content() + assert expected_result == actual_result