code-intelligence.com/cifuzz@v0.40.0/internal/cmd/coverage/summary/jacoco.go (about) 1 package summary 2 3 import ( 4 "encoding/xml" 5 "fmt" 6 "io" 7 8 "code-intelligence.com/cifuzz/pkg/log" 9 ) 10 11 type jacocoCounter struct { 12 Text string `xml:",chardata"` 13 Type string `xml:"type,attr"` 14 Missed int `xml:"missed,attr"` 15 Covered int `xml:"covered,attr"` 16 } 17 18 type jacocoReport struct { 19 XMLName xml.Name `xml:"report"` 20 Text string `xml:",chardata"` 21 Name string `xml:"name,attr"` 22 Sessioninfo []struct { 23 Text string `xml:",chardata"` 24 ID string `xml:"id,attr"` 25 Start string `xml:"start,attr"` 26 Dump string `xml:"dump,attr"` 27 } `xml:"sessioninfo"` 28 Packages []struct { 29 Text string `xml:",chardata"` 30 Name string `xml:"name,attr"` 31 Classes []struct { 32 Text string `xml:",chardata"` 33 Name string `xml:"name,attr"` 34 Sourcefilename string `xml:"sourcefilename,attr"` 35 Method []struct { 36 Text string `xml:",chardata"` 37 Name string `xml:"name,attr"` 38 Desc string `xml:"desc,attr"` 39 Line string `xml:"line,attr"` 40 Counter []jacocoCounter `xml:"counter"` 41 } `xml:"method"` 42 Counter []jacocoCounter `xml:"counter"` 43 } `xml:"class"` 44 Sourcefiles []struct { 45 Text string `xml:",chardata"` 46 Name string `xml:"name,attr"` 47 Line []struct { 48 Text string `xml:",chardata"` 49 Nr string `xml:"nr,attr"` 50 Mi string `xml:"mi,attr"` 51 Ci string `xml:"ci,attr"` 52 Mb string `xml:"mb,attr"` 53 Cb string `xml:"cb,attr"` 54 } `xml:"line"` 55 Counter []jacocoCounter `xml:"counter"` 56 } `xml:"sourcefile"` 57 Counter []jacocoCounter `xml:"counter"` 58 } `xml:"package"` 59 Counter []jacocoCounter `xml:"counter"` 60 } 61 62 func countJacoco(c *Coverage, counter *jacocoCounter) { 63 switch counter.Type { 64 case "LINE": 65 c.LinesFound += counter.Covered + counter.Missed 66 c.LinesHit += counter.Covered 67 case "BRANCH": 68 c.BranchesFound += counter.Covered + counter.Missed 69 c.BranchesHit += counter.Covered 70 case "METHOD": 71 c.FunctionsFound += counter.Covered + counter.Missed 72 c.FunctionsHit += counter.Covered 73 } 74 } 75 76 // ParseJacocoXML takes a jacoco xml report and turns it into 77 // the `CoverageSummary` struct. The parsing is as forgiving 78 // as possible. It will output debug/error logs instead of 79 // failing, with the goal to gather as much information as 80 // possible 81 func ParseJacocoXML(in io.Reader) *CoverageSummary { 82 summary := &CoverageSummary{ 83 Total: &Coverage{}, 84 } 85 86 output, err := io.ReadAll(in) 87 if err != nil { 88 log.Debugf("Unable to read jacoco xml report") 89 return summary 90 } 91 report := &jacocoReport{} 92 err = xml.Unmarshal(output, report) 93 if err != nil { 94 log.Debugf("Unable to parse jacoco xml report") 95 return summary 96 } 97 98 var currentFile *FileCoverage 99 for _, xmlPackage := range report.Packages { 100 for _, sourcefile := range xmlPackage.Sourcefiles { 101 currentFile = &FileCoverage{ 102 Filename: fmt.Sprintf("%s/%s", xmlPackage.Name, sourcefile.Name), 103 Coverage: &Coverage{}, 104 } 105 for _, counter := range sourcefile.Counter { 106 countJacoco(summary.Total, &counter) 107 countJacoco(currentFile.Coverage, &counter) 108 } 109 summary.Files = append(summary.Files, currentFile) 110 } 111 } 112 113 return summary 114 }