-
Notifications
You must be signed in to change notification settings - Fork 16
Description
Currently, the commentator only supports parsing term coverage reports (the default report type), which do not support a destination file. As a result, you must redirect your test output to a file for the commentator to be able to load that report. This is a pain if you also rely on the output being visible in your GH action (but you can use pytest | tee coverage.txt to avoid having to run the tests twice).
But, pytest-cov lets you set the type of report it generates (more than once to produce multple outputs), and the annotate, html and xml reports all support a destination. E.g. pytest --cov-report=xml:coverage.xml will generate a coverage.xml file.
The XML output is the most suitable to parsing; the downside is that there is no platform information in that output. I don't think that's really a big problem. You'll have to run the file through an XML parser, of course.
You can otherwise produce the exact same output as the default term report if you parse the XML file by iterating over all packages -> package -> classes -> class tags. For the Name, Stmts, Miss, Branch, BrPart and Cover columns, you need to collect the following information:
-
Name: thefilenameattribute of theclasselement -
Stmts: count the number of childlineelements under theclasselement. -
Miss: count the number of childlineelements with thehitsattribute set to0, or alternatively, withhitsnot set to1(hitsis always1or0). -
Branch: for all childlineelements withbranch="true", parse thecondition-coveragetag string, using the regex^\d+% \((?P<brachhits>:\d+)/(?P<branches>\d+)\)$, and sum thebranchesnumbers. E.g. for the value100% (2/2),branchesis2. -
BrPart: for all childlineelements withbranch="true", parse thecondition-coveragetag string, using the regex^\d*% \((?P<brachhits>:\d+)/(?P<branches>\d+)$, and only ifbranchhitsis not equal tobranches, sum thebranchhitsvalue (these are partial branch hits). E.g. for the value50% (1/2),branchhitsis1, and not equal tobranches=2, so count1partial branch hit. For0% (0/2)or100% (2/2), you ignore thebranchhitsvalue. -
Cover: when processing all childlineelements, the coverage is calculated across 4 different numbers:- total lines (the
Stmtsvalue) - total branches (the
Branchvalue) - total hits (
Stmts-Miss, all lines withhits="1") - total branch hits (all
branchhitsvalues. This differs from theBrPartvalue which only sums non-zerobranchhitsvalues that are not equal tobranches).
The percentage is then calculated using
(total hits + total branch hits) / (total lines + total branches) * 100. This is a fraction between 0 and 100. If the value is not exactly 0 but below 1, display1. If the value is not exactly 100, but above 99, display 99. All other values are rounded to the nearest whole number. The extra rules for1and99there prevent0.5becoming0and99.5becoming100.This is detailed in the coverage FAQ and verified by reading the
results.pysource code (specifically theratio_coveredanddisplay_coveredmethods). - total lines (the
The term report can be configured to show missing line numbers too, I didn't search for how those are summarised (look for the format_lines() function). The coverage percentage precision is also adjustable, altering the near-0 and near-100 rules. I used the default rules above.
The advantage of all this work is that you can then display any Cobertura-compatible XML coverage report in this way.