Coverage for tests / test_lcov.py: 100.000%
174 statements
« prev ^ index » next coverage.py v7.12.1a0.dev1, created at 2025-11-30 17:57 +0000
« prev ^ index » next coverage.py v7.12.1a0.dev1, created at 2025-11-30 17:57 +0000
1# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2# For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt
4"""Test LCOV-based summary reporting for coverage.py."""
6from __future__ import annotations 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
8import math 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
9import textwrap 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
11import coverage 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
13from tests.coveragetest import CoverageTest 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
16class LcovTest(CoverageTest): 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
17 """Tests of the LCOV reports from coverage.py."""
19 def create_initial_files(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
20 """
21 Helper for tests that handles the common ceremony so the tests can
22 show the consequences of changes in the setup.
23 """
24 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
25 "main_file.py",
26 """\
27 def cuboid_volume(l):
28 return (l*l*l)
30 def IsItTrue():
31 return True
32 """,
33 )
35 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
36 "test_file.py",
37 """\
38 from main_file import cuboid_volume
39 import unittest
41 class TestCuboid(unittest.TestCase):
42 def test_volume(self):
43 self.assertAlmostEqual(cuboid_volume(2),8)
44 self.assertAlmostEqual(cuboid_volume(1),1)
45 self.assertAlmostEqual(cuboid_volume(0),0)
46 self.assertAlmostEqual(cuboid_volume(5.5),166.375)
47 """,
48 )
50 def get_lcov_report_content(self, filename: str = "coverage.lcov") -> str: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
51 """Return the content of an LCOV report."""
52 with open(filename, encoding="utf-8") as file: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
53 return file.read() 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
55 def test_lone_file(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
56 # For a single file with a couple of functions, the lcov should cover
57 # the function definitions themselves, but not the returns.
58 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
59 "main_file.py",
60 """\
61 def cuboid_volume(l):
62 return (l*l*l)
64 def IsItTrue():
65 return True
66 """,
67 )
68 expected_result = textwrap.dedent("""\ 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
69 SF:main_file.py
70 DA:1,1
71 DA:2,0
72 DA:4,1
73 DA:5,0
74 LF:4
75 LH:2
76 FN:1,2,cuboid_volume
77 FNDA:0,cuboid_volume
78 FN:4,5,IsItTrue
79 FNDA:0,IsItTrue
80 FNF:2
81 FNH:0
82 end_of_record
83 """)
84 self.assert_doesnt_exist(".coverage") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
85 cov = coverage.Coverage(source=["."]) 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
86 self.start_import_stop(cov, "main_file") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
87 pct = cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
88 assert pct == 50.0 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
89 actual_result = self.get_lcov_report_content() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
90 assert expected_result == actual_result 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
92 def test_line_checksums(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
93 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
94 "main_file.py",
95 """\
96 def cuboid_volume(l):
97 return (l*l*l)
99 def IsItTrue():
100 return True
101 """,
102 )
103 self.make_file(".coveragerc", "[lcov]\nline_checksums = true\n") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
104 self.assert_doesnt_exist(".coverage") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
105 cov = coverage.Coverage(source=["."]) 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
106 self.start_import_stop(cov, "main_file") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
107 pct = cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
108 assert pct == 50.0 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
109 expected_result = textwrap.dedent("""\ 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
110 SF:main_file.py
111 DA:1,1,7URou3io0zReBkk69lEb/Q
112 DA:2,0,Xqj6H1iz/nsARMCAbE90ng
113 DA:4,1,ilhb4KUfytxtEuClijZPlQ
114 DA:5,0,LWILTcvARcydjFFyo9qM0A
115 LF:4
116 LH:2
117 FN:1,2,cuboid_volume
118 FNDA:0,cuboid_volume
119 FN:4,5,IsItTrue
120 FNDA:0,IsItTrue
121 FNF:2
122 FNH:0
123 end_of_record
124 """)
125 actual_result = self.get_lcov_report_content() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
126 assert expected_result == actual_result 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
128 def test_simple_line_coverage_two_files(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
129 # Test that line coverage is created when coverage is run,
130 # and matches the output of the file below.
131 self.create_initial_files() 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
132 self.assert_doesnt_exist(".coverage") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
133 self.make_file(".coveragerc", "[lcov]\noutput = data.lcov\n") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
134 cov = coverage.Coverage(source=".") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
135 self.start_import_stop(cov, "test_file") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
136 pct = cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
137 assert pct == 50.0 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
138 self.assert_exists("data.lcov") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
139 expected_result = textwrap.dedent("""\ 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
140 SF:main_file.py
141 DA:1,1
142 DA:2,0
143 DA:4,1
144 DA:5,0
145 LF:4
146 LH:2
147 FN:1,2,cuboid_volume
148 FNDA:0,cuboid_volume
149 FN:4,5,IsItTrue
150 FNDA:0,IsItTrue
151 FNF:2
152 FNH:0
153 end_of_record
154 SF:test_file.py
155 DA:1,1
156 DA:2,1
157 DA:4,1
158 DA:5,1
159 DA:6,0
160 DA:7,0
161 DA:8,0
162 DA:9,0
163 LF:8
164 LH:4
165 FN:5,9,TestCuboid.test_volume
166 FNDA:0,TestCuboid.test_volume
167 FNF:1
168 FNH:0
169 end_of_record
170 """)
171 actual_result = self.get_lcov_report_content(filename="data.lcov") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
172 assert expected_result == actual_result 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
174 def test_branch_coverage_one_file(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
175 # Test that the reporter produces valid branch coverage.
176 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
177 "main_file.py",
178 """\
179 def is_it_x(x):
180 if x == 3:
181 return x
182 else:
183 return False
184 """,
185 )
186 self.assert_doesnt_exist(".coverage") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
187 cov = coverage.Coverage(branch=True, source=".") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
188 self.start_import_stop(cov, "main_file") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
189 pct = cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
190 assert math.isclose(pct, 16.666666666666668) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
191 self.assert_exists("coverage.lcov") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
192 expected_result = textwrap.dedent("""\ 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
193 SF:main_file.py
194 DA:1,1
195 DA:2,0
196 DA:3,0
197 DA:5,0
198 LF:4
199 LH:1
200 FN:1,5,is_it_x
201 FNDA:0,is_it_x
202 FNF:1
203 FNH:0
204 BRDA:2,0,jump to line 3,-
205 BRDA:2,0,jump to line 5,-
206 BRF:2
207 BRH:0
208 end_of_record
209 """)
210 actual_result = self.get_lcov_report_content() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
211 assert expected_result == actual_result 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
213 def test_branch_coverage_two_files(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
214 # Test that valid branch coverage is generated
215 # in the case of two files.
216 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
217 "main_file.py",
218 """\
219 def is_it_x(x):
220 if x == 3:
221 return x
222 else:
223 return False
224 """,
225 )
227 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
228 "test_file.py",
229 """\
230 from main_file import *
231 import unittest
233 class TestIsItX(unittest.TestCase):
234 def test_is_it_x(self):
235 self.assertEqual(is_it_x(3), 3)
236 self.assertEqual(is_it_x(4), False)
237 """,
238 )
239 self.assert_doesnt_exist(".coverage") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
240 cov = coverage.Coverage(branch=True, source=".") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
241 self.start_import_stop(cov, "test_file") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
242 pct = cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
243 assert math.isclose(pct, 41.666666666666664) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
244 self.assert_exists("coverage.lcov") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
245 expected_result = textwrap.dedent("""\ 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
246 SF:main_file.py
247 DA:1,1
248 DA:2,0
249 DA:3,0
250 DA:5,0
251 LF:4
252 LH:1
253 FN:1,5,is_it_x
254 FNDA:0,is_it_x
255 FNF:1
256 FNH:0
257 BRDA:2,0,jump to line 3,-
258 BRDA:2,0,jump to line 5,-
259 BRF:2
260 BRH:0
261 end_of_record
262 SF:test_file.py
263 DA:1,1
264 DA:2,1
265 DA:4,1
266 DA:5,1
267 DA:6,0
268 DA:7,0
269 LF:6
270 LH:4
271 FN:5,7,TestIsItX.test_is_it_x
272 FNDA:0,TestIsItX.test_is_it_x
273 FNF:1
274 FNH:0
275 end_of_record
276 """)
277 actual_result = self.get_lcov_report_content() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
278 assert expected_result == actual_result 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
280 def test_half_covered_branch(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
281 # Test that for a given branch that is only half covered,
282 # the block numbers remain the same, and produces valid lcov.
283 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
284 "main_file.py",
285 """\
286 something = True
288 if something:
289 print("Yes, something")
290 else:
291 print("No, nothing")
292 """,
293 )
294 self.assert_doesnt_exist(".coverage") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
295 cov = coverage.Coverage(branch=True, source=".") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
296 self.start_import_stop(cov, "main_file") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
297 pct = cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
298 assert math.isclose(pct, 66.66666666666667) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
299 self.assert_exists("coverage.lcov") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
300 expected_result = textwrap.dedent("""\ 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
301 SF:main_file.py
302 DA:1,1
303 DA:3,1
304 DA:4,1
305 DA:6,0
306 LF:4
307 LH:3
308 BRDA:3,0,jump to line 4,1
309 BRDA:3,0,jump to line 6,0
310 BRF:2
311 BRH:1
312 end_of_record
313 """)
314 actual_result = self.get_lcov_report_content() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
315 assert expected_result == actual_result 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
317 def test_empty_init_files(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
318 # Test that an empty __init__.py still generates a (vacuous)
319 # coverage record.
320 self.make_file("__init__.py", "") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
321 self.assert_doesnt_exist(".coverage") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
322 cov = coverage.Coverage(branch=True, source=".") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
323 self.start_import_stop(cov, "__init__") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
324 pct = cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
325 assert pct == 0.0 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
326 self.assert_exists("coverage.lcov") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
327 expected_result = textwrap.dedent("""\ 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
328 SF:__init__.py
329 end_of_record
330 """)
331 actual_result = self.get_lcov_report_content() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
332 assert expected_result == actual_result 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
334 def test_empty_init_file_skipped(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
335 # Test that the lcov reporter honors skip_empty. Because skip_empty
336 # keys off the overall number of lines of code, the result in this
337 # case will be the same regardless of the age of the Python interpreter.
338 self.make_file("__init__.py", "") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
339 self.make_file(".coveragerc", "[report]\nskip_empty = True\n") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
340 self.assert_doesnt_exist(".coverage") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
341 cov = coverage.Coverage(branch=True, source=".") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
342 self.start_import_stop(cov, "__init__") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
343 pct = cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
344 assert pct == 0.0 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
345 self.assert_exists("coverage.lcov") 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
346 expected_result = "" 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
347 actual_result = self.get_lcov_report_content() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
348 assert expected_result == actual_result 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
350 def test_excluded_lines(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
351 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
352 ".coveragerc",
353 """\
354 [report]
355 exclude_lines = foo
356 """,
357 )
358 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
359 "runme.py",
360 """\
361 s = "Hello 1"
362 t = "foo is ignored 2"
363 if s.upper() == "BYE 3":
364 i_am_missing_4()
365 foo_is_missing_5()
366 print("Done 6")
367 # foo 7
368 # line 8
369 """,
370 )
371 cov = coverage.Coverage(source=".", branch=True) 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
372 self.start_import_stop(cov, "runme") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
373 cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
374 expected_result = textwrap.dedent("""\ 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
375 SF:runme.py
376 DA:1,1
377 DA:3,1
378 DA:4,0
379 DA:6,1
380 LF:4
381 LH:3
382 BRDA:3,0,jump to line 4,0
383 BRDA:3,0,jump to line 6,1
384 BRF:2
385 BRH:1
386 end_of_record
387 """)
388 actual_result = self.get_lcov_report_content() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
389 assert expected_result == actual_result 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
391 def test_exit_branches(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
392 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
393 "runme.py",
394 """\
395 def foo(a):
396 if a:
397 print(f"{a!r} is truthy")
398 foo(True)
399 foo(False)
400 foo([])
401 foo([0])
402 """,
403 )
404 cov = coverage.Coverage(source=".", branch=True) 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
405 self.start_import_stop(cov, "runme") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
406 cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
407 expected_result = textwrap.dedent("""\ 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
408 SF:runme.py
409 DA:1,1
410 DA:2,1
411 DA:3,1
412 DA:4,1
413 DA:5,1
414 DA:6,1
415 DA:7,1
416 LF:7
417 LH:7
418 FN:1,3,foo
419 FNDA:1,foo
420 FNF:1
421 FNH:1
422 BRDA:2,0,jump to line 3,1
423 BRDA:2,0,return from function 'foo',1
424 BRF:2
425 BRH:2
426 end_of_record
427 """)
428 actual_result = self.get_lcov_report_content() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
429 assert expected_result == actual_result 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
431 def test_genexpr_exit_arcs_pruned_full_coverage(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
432 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
433 "runme.py",
434 """\
435 def foo(a):
436 if any(x > 0 for x in a):
437 print(f"{a!r} has positives")
438 foo([])
439 foo([0])
440 foo([0,1])
441 foo([0,-1])
442 """,
443 )
444 cov = coverage.Coverage(source=".", branch=True) 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
445 self.start_import_stop(cov, "runme") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
446 cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
447 expected_result = textwrap.dedent("""\ 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
448 SF:runme.py
449 DA:1,1
450 DA:2,1
451 DA:3,1
452 DA:4,1
453 DA:5,1
454 DA:6,1
455 DA:7,1
456 LF:7
457 LH:7
458 FN:1,3,foo
459 FNDA:1,foo
460 FNF:1
461 FNH:1
462 BRDA:2,0,jump to line 3,1
463 BRDA:2,0,return from function 'foo',1
464 BRF:2
465 BRH:2
466 end_of_record
467 """)
468 actual_result = self.get_lcov_report_content() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
469 assert expected_result == actual_result 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
471 def test_genexpr_exit_arcs_pruned_never_true(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
472 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
473 "runme.py",
474 """\
475 def foo(a):
476 if any(x > 0 for x in a):
477 print(f"{a!r} has positives")
478 foo([])
479 foo([0])
480 """,
481 )
482 cov = coverage.Coverage(source=".", branch=True) 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
483 self.start_import_stop(cov, "runme") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
484 cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
485 expected_result = textwrap.dedent("""\ 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
486 SF:runme.py
487 DA:1,1
488 DA:2,1
489 DA:3,0
490 DA:4,1
491 DA:5,1
492 LF:5
493 LH:4
494 FN:1,3,foo
495 FNDA:1,foo
496 FNF:1
497 FNH:1
498 BRDA:2,0,jump to line 3,0
499 BRDA:2,0,return from function 'foo',1
500 BRF:2
501 BRH:1
502 end_of_record
503 """)
504 actual_result = self.get_lcov_report_content() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
505 assert expected_result == actual_result 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
507 def test_genexpr_exit_arcs_pruned_always_true(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
508 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
509 "runme.py",
510 """\
511 def foo(a):
512 if any(x > 0 for x in a):
513 print(f"{a!r} has positives")
514 foo([1])
515 foo([1,2])
516 """,
517 )
518 cov = coverage.Coverage(source=".", branch=True) 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
519 self.start_import_stop(cov, "runme") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
520 cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
521 expected_result = textwrap.dedent("""\ 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
522 SF:runme.py
523 DA:1,1
524 DA:2,1
525 DA:3,1
526 DA:4,1
527 DA:5,1
528 LF:5
529 LH:5
530 FN:1,3,foo
531 FNDA:1,foo
532 FNF:1
533 FNH:1
534 BRDA:2,0,jump to line 3,1
535 BRDA:2,0,return from function 'foo',0
536 BRF:2
537 BRH:1
538 end_of_record
539 """)
540 actual_result = self.get_lcov_report_content() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
541 assert expected_result == actual_result 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
543 def test_genexpr_exit_arcs_pruned_not_reached(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
544 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
545 "runme.py",
546 """\
547 def foo(a):
548 if any(x > 0 for x in a):
549 print(f"{a!r} has positives")
550 """,
551 )
552 cov = coverage.Coverage(source=".", branch=True) 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
553 self.start_import_stop(cov, "runme") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
554 cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
555 expected_result = textwrap.dedent("""\ 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
556 SF:runme.py
557 DA:1,1
558 DA:2,0
559 DA:3,0
560 LF:3
561 LH:1
562 FN:1,3,foo
563 FNDA:0,foo
564 FNF:1
565 FNH:0
566 BRDA:2,0,jump to line 3,-
567 BRDA:2,0,return from function 'foo',-
568 BRF:2
569 BRH:0
570 end_of_record
571 """)
572 actual_result = self.get_lcov_report_content() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
573 assert expected_result == actual_result 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
575 def test_always_raise(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
576 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
577 "always_raise.py",
578 """\
579 try:
580 if not_defined:
581 print("Yes")
582 else:
583 print("No")
584 except Exception:
585 pass
586 """,
587 )
588 cov = coverage.Coverage(source=".", branch=True) 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
589 self.start_import_stop(cov, "always_raise") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
590 cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
591 expected_result = textwrap.dedent("""\ 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
592 SF:always_raise.py
593 DA:1,1
594 DA:2,1
595 DA:3,0
596 DA:5,0
597 DA:6,1
598 DA:7,1
599 LF:6
600 LH:4
601 BRDA:2,0,jump to line 3,-
602 BRDA:2,0,jump to line 5,-
603 BRF:2
604 BRH:0
605 end_of_record
606 """)
607 actual_result = self.get_lcov_report_content() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
608 assert expected_result == actual_result 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
610 def test_multiline_conditions(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
611 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
612 "multi.py",
613 """\
614 def fun(x):
615 if (
616 x
617 ):
618 print("got here")
619 """,
620 )
621 cov = coverage.Coverage(source=".", branch=True) 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
622 self.start_import_stop(cov, "multi") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
623 cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
624 lcov = self.get_lcov_report_content() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
625 assert "BRDA:2,0,return from function 'fun',-" in lcov 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
627 def test_module_exit(self) -> None: 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
628 self.make_file( 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
629 "modexit.py",
630 """\
631 #! /usr/bin/env python
632 def foo():
633 return bar(
634 )
635 if "x" == "y": # line 5
636 foo()
637 """,
638 )
639 cov = coverage.Coverage(source=".", branch=True) 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
640 self.start_import_stop(cov, "modexit") 1abcdefghijklmnopqrstuvwxyzABCDEF5GH6IJ7KL8MN9OP!QR#ST$UV%WX'YZ(01)234
641 cov.lcov_report() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
642 lcov = self.get_lcov_report_content() 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
643 print(lcov) 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234
644 assert "BRDA:5,0,exit the module,1" in lcov 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234