eric7/DebugClients/Python/coverage/lcovreport.py

Sun, 20 Mar 2022 17:49:44 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 20 Mar 2022 17:49:44 +0100
branch
eric7
changeset 8991
2fc945191992
permissions
-rw-r--r--

Third Party packages
- upgraded coverage to 6.3.2

8991
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
2 # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
3
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
4 """LCOV reporting for coverage.py."""
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
5
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
6 import sys
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
7 import base64
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
8 from hashlib import md5
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
9
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
10 from coverage.report import get_analysis_to_report
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
11
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
12
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
13 class LcovReporter:
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
14 """A reporter for writing LCOV coverage reports."""
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
15
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
16 report_type = "LCOV report"
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
17
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
18 def __init__(self, coverage):
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
19 self.coverage = coverage
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
20 self.config = self.coverage.config
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
21
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
22 def report(self, morfs, outfile=None):
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
23 """Renders the full lcov report.
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
24
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
25 'morfs' is a list of modules or filenames
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
26
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
27 outfile is the file object to write the file into.
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
28 """
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
29
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
30 self.coverage.get_data()
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
31 outfile = outfile or sys.stdout
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
32
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
33 for fr, analysis in get_analysis_to_report(self.coverage, morfs):
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
34 self.get_lcov(fr, analysis, outfile)
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
35
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
36 def get_lcov(self, fr, analysis, outfile=None):
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
37 """Produces the lcov data for a single file.
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
38
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
39 This currently supports both line and branch coverage,
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
40 however function coverage is not supported.
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
41 """
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
42 outfile.write("TN:\n")
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
43 outfile.write(f"SF:{fr.relative_filename()}\n")
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
44 source_lines = fr.source().splitlines()
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
45
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
46 for covered in sorted(analysis.executed):
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
47 # Note: Coverage.py currently only supports checking *if* a line
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
48 # has been executed, not how many times, so we set this to 1 for
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
49 # nice output even if it's technically incorrect.
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
50
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
51 # The lines below calculate a 64-bit encoded md5 hash of the line
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
52 # corresponding to the DA lines in the lcov file, for either case
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
53 # of the line being covered or missed in coverage.py. The final two
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
54 # characters of the encoding ("==") are removed from the hash to
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
55 # allow genhtml to run on the resulting lcov file.
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
56 if source_lines:
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
57 line = source_lines[covered-1].encode("utf-8")
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
58 else:
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
59 line = b""
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
60 hashed = base64.b64encode(md5(line).digest()).decode().rstrip("=")
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
61 outfile.write(f"DA:{covered},1,{hashed}\n")
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
62
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
63 for missed in sorted(analysis.missing):
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
64 assert source_lines
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
65 line = source_lines[missed-1].encode("utf-8")
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
66 hashed = base64.b64encode(md5(line).digest()).decode().rstrip("=")
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
67 outfile.write(f"DA:{missed},0,{hashed}\n")
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
68
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
69 outfile.write(f"LF:{len(analysis.statements)}\n")
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
70 outfile.write(f"LH:{len(analysis.executed)}\n")
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
71
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
72 # More information dense branch coverage data.
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
73 missing_arcs = analysis.missing_branch_arcs()
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
74 executed_arcs = analysis.executed_branch_arcs()
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
75 for block_number, block_line_number in enumerate(
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
76 sorted(analysis.branch_stats().keys())
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
77 ):
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
78 for branch_number, line_number in enumerate(
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
79 sorted(missing_arcs[block_line_number])
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
80 ):
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
81 # The exit branches have a negative line number,
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
82 # this will not produce valid lcov. Setting
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
83 # the line number of the exit branch to 0 will allow
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
84 # for valid lcov, while preserving the data.
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
85 line_number = max(line_number, 0)
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
86 outfile.write(f"BRDA:{line_number},{block_number},{branch_number},-\n")
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
87
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
88 # The start value below allows for the block number to be
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
89 # preserved between these two for loops (stopping the loop from
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
90 # resetting the value of the block number to 0).
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
91 for branch_number, line_number in enumerate(
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
92 sorted(executed_arcs[block_line_number]),
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
93 start=len(missing_arcs[block_line_number]),
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
94 ):
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
95 line_number = max(line_number, 0)
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
96 outfile.write(f"BRDA:{line_number},{block_number},{branch_number},1\n")
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
97
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
98 # Summary of the branch coverage.
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
99 if analysis.has_arcs():
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
100 branch_stats = analysis.branch_stats()
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
101 brf = sum(t for t, k in branch_stats.values())
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
102 brh = brf - sum(t - k for t, k in branch_stats.values())
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
103 outfile.write(f"BRF:{brf}\n")
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
104 outfile.write(f"BRH:{brh}\n")
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
105
2fc945191992 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
106 outfile.write("end_of_record\n")

eric ide

mercurial