github.com/covergates/covergates@v0.2.2-0.20201009050117-42ef8a19fb95/service/python/report.go (about) 1 package python 2 3 import ( 4 "context" 5 "encoding/xml" 6 "io" 7 "io/ioutil" 8 "path/filepath" 9 10 "github.com/covergates/covergates/core" 11 "github.com/covergates/covergates/service/common" 12 ) 13 14 // CoverageService of python 15 type CoverageService struct{} 16 17 type coverage struct { 18 XMLName xml.Name `xml:"coverage"` 19 Sources []string `xml:"sources>source"` 20 Packages []pkg `xml:"packages>package"` 21 } 22 23 type pkg struct { 24 Name string `xml:"name,attr"` 25 Classes []class `xml:"classes>class"` 26 } 27 28 type class struct { 29 Name string `xml:"filename,attr"` 30 Lines []line `xml:"lines>line"` 31 LineRate float64 `xml:"line-rate,attr"` 32 } 33 34 type line struct { 35 Number int `xml:"number,attr"` 36 Hits int `xml:"hits,attr"` 37 } 38 39 // Report of python coverage 40 func (s *CoverageService) Report(ctx context.Context, reader io.Reader) (*core.CoverageReport, error) { 41 data, err := ioutil.ReadAll(reader) 42 if err != nil { 43 return nil, err 44 } 45 c := &coverage{} 46 if err := xml.Unmarshal(data, c); err != nil { 47 return nil, err 48 } 49 result := make([]*core.File, 0) 50 for _, pkg := range c.Packages { 51 files := pkg.toFiles(c.Source()) 52 result = append(result, files...) 53 } 54 report := &core.CoverageReport{ 55 Type: core.ReportPython, 56 Files: result, 57 } 58 report.StatementCoverage = report.ComputeStatementCoverage() 59 return report, nil 60 } 61 62 //Find python coverage report in xml format 63 func (s *CoverageService) Find(ctx context.Context, path string) (string, error) { 64 return common.FindReport(path, "coverage.xml") 65 } 66 67 // Open reader of python coverage report 68 func (s *CoverageService) Open(ctx context.Context, path string) (io.Reader, error) { 69 return common.OpenFileReader(path) 70 } 71 72 func (c coverage) Source() string { 73 return c.Sources[0] 74 } 75 76 func (p pkg) toFiles(parent string) []*core.File { 77 files := make([]*core.File, len(p.Classes)) 78 for i, class := range p.Classes { 79 statementHist := make([]*core.StatementHit, len(class.Lines)) 80 for j, line := range class.Lines { 81 statementHist[j] = &core.StatementHit{ 82 Hits: line.Hits, 83 LineNumber: line.Number, 84 } 85 } 86 files[i] = &core.File{ 87 Name: filepath.Join(parent, class.Name), 88 StatementHits: statementHist, 89 StatementCoverage: class.LineRate, 90 } 91 } 92 return files 93 }