Skip to content

Commit

Permalink
feat: add support to extract coverage jacoco format for utg (keploy#2253
Browse files Browse the repository at this point in the history
)

* add: support for jacoco format

Signed-off-by: shivamsouravjha <[email protected]>

* undo: code comment

Signed-off-by: shivamsouravjha <[email protected]>

---------

Signed-off-by: shivamsouravjha <[email protected]>
  • Loading branch information
shivamsouravjha authored Aug 30, 2024
1 parent 4f777b8 commit a5364d7
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 0 deletions.
54 changes: 54 additions & 0 deletions pkg/models/ut.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,57 @@ type Line struct {
Number int `xml:"number,attr"`
Hits int `xml:"hits,attr"`
}

type Jacoco struct {
Name string `xml:"name,attr"`
XMLName xml.Name `xml:"report"`
Packages []JacocoPackage `xml:"package"`
SessionInfo []SessionInfo `xml:"sessioninfo"`
}

type SessionInfo struct {
ID string `xml:"id,attr"`
Start string `xml:"start,attr"`
Dump string `xml:"dump,attr"`
}

type JacocoPackage struct {
Name string `xml:"name,attr"`
Classes []JacocoClass `xml:"class"`
Counters []Counter `xml:"counter"`
SourceFiles []JacocoSourceFile `xml:"sourcefile"` // Adding this field to capture source files
}

type JacocoSourceFile struct {
Name string `xml:"name,attr"`
Lines []JacocoLine `xml:"line"`
Counters []Counter `xml:"counter"`
}

type JacocoClass struct {
Name string `xml:"name,attr"`
SourceFile string `xml:"sourcefilename,attr"`
Methods []JacocoMethod `xml:"method"`
Lines []JacocoLine `xml:"line"` // This is where JacocoLine is used
}

type JacocoMethod struct {
Name string `xml:"name,attr"`
Descriptor string `xml:"desc,attr"`
Line string `xml:"line,attr"`
Counters []Counter `xml:"counter"`
}

type JacocoLine struct {
Number string `xml:"nr,attr"`
MissedInstructions string `xml:"mi,attr"`
CoveredInstructions string `xml:"ci,attr"`
MissedBranches string `xml:"mb,attr"`
CoveredBranches string `xml:"cb,attr"`
}

type Counter struct {
Type string `xml:"type,attr"`
Missed string `xml:"missed,attr"`
Covered string `xml:"covered,attr"`
}
95 changes: 95 additions & 0 deletions pkg/service/utgen/coverage.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/xml"
"fmt"
"os"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -67,6 +68,8 @@ func (cp *CoverageProcessor) ParseCoverageReport() (*models.CoverageResult, erro
switch cp.Format {
case "cobertura":
return cp.ParseCoverageReportCobertura()
case "jacoco":
return cp.ParseCoverageReportJacoco()
case "lcov":
return nil, fmt.Errorf("parsing for %s coverage reports is not implemented yet", cp.Format)
default:
Expand Down Expand Up @@ -152,3 +155,95 @@ func (cp *CoverageProcessor) ParseCoverageReportCobertura() (*models.CoverageRes

return coverageResult, nil
}

func (cp *CoverageProcessor) ParseCoverageReportJacoco() (*models.CoverageResult, error) {

filesToCover := make([]string, 0)
// Open the XML file
xmlFile, err := os.Open(cp.ReportPath)
if err != nil {
return nil, err
}

defer func() {
if err := xmlFile.Close(); err != nil {
return
}
}()

// Decode the XML file into a Coverage struct
var jacoco models.Jacoco
if err := xml.NewDecoder(xmlFile).Decode(&jacoco); err != nil {
return nil, err
}

// Find coverage for the specified file
var linesCovered, linesMissed []int
var totalLines, coveredLines int
var filteredSourceFiles []models.JacocoSourceFile

for _, pkg := range jacoco.Packages {
for _, src := range pkg.SourceFiles {
if cp.SrcPath == "." {
filesToCover = append(filesToCover, src.Name)
}
if strings.HasSuffix(src.Name, cp.SrcPath) {
for _, line := range src.Lines {
totalLines++
missedInstructions, errMissed := strconv.Atoi(line.MissedInstructions)
coveredInstructions, errCovered := strconv.Atoi(line.CoveredInstructions)
if errMissed != nil || errCovered != nil {
// Handle conversion error
continue
}
if coveredInstructions > 0 {
coveredLines++
lineNumber, err := strconv.Atoi(line.Number)
if err == nil {
linesCovered = append(linesCovered, lineNumber)
}
} else if missedInstructions > 0 {
// Use missedInstructions to check if a line has any missed instructions
lineNumber, err := strconv.Atoi(line.Number)
if err == nil {
linesMissed = append(linesMissed, lineNumber)
}
}
}
filteredSourceFiles = append(filteredSourceFiles, src)
break
}
}
}
var coveragePercentage float64
if totalLines > 0 {
coveragePercentage = float64(len(linesCovered)) / float64(totalLines)
}

// Reconstruct the coverage report with only the filtered class
filteredCov := models.Jacoco{
Packages: []models.JacocoPackage{
{
SourceFiles: filteredSourceFiles,
},
},
}

// Encode the filtered coverage report to XML
var filteredBuf bytes.Buffer
xmlEncoder := xml.NewEncoder(&filteredBuf)
xmlEncoder.Indent("", " ")
if err := xmlEncoder.Encode(filteredCov); err != nil {
return nil, err
}

coverageResult := &models.CoverageResult{
LinesCovered: linesCovered,
LinesMissed: linesMissed,
Coverage: coveragePercentage,
Files: filesToCover,
ReportContent: filteredBuf.String(),
}

return coverageResult, nil
}

0 comments on commit a5364d7

Please sign in to comment.