Skip to content

Commit

Permalink
Merge c42e4b7 into e2e9dff
Browse files Browse the repository at this point in the history
  • Loading branch information
msabramo committed Feb 15, 2018
2 parents e2e9dff + c42e4b7 commit 2dc92ea
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 16 deletions.
126 changes: 124 additions & 2 deletions cobertura.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type Class struct {
BranchRate float32 `xml:"branch-rate,attr"`
Complexity float32 `xml:"complexity,attr"`
Methods []*Method `xml:"methods>method"`
Lines []*Line `xml:"lines>line"`
Lines Lines `xml:"lines>line"`
}

type Method struct {
Expand All @@ -47,10 +47,132 @@ type Method struct {
LineRate float32 `xml:"line-rate,attr"`
BranchRate float32 `xml:"branch-rate,attr"`
Complexity float32 `xml:"complexity,attr"`
Lines []*Line `xml:"lines>line"`
Lines Lines `xml:"lines>line"`
}

type Line struct {
Number int `xml:"number,attr"`
Hits int64 `xml:"hits,attr"`
}

// Lines is a slice of Line pointers, with some convenience methods
type Lines []*Line

// HitRate returns a float32 from 0.0 to 1.0 representing what fraction of lines
// have hits
func (lines Lines) HitRate() (hitRate float32) {
return float32(lines.NumLinesWithHits()) / float32(len(lines))
}

// NumLines returns the number of lines
func (lines Lines) NumLines() int64 {
return int64(len(lines))
}

// NumLinesWithHits returns the number of lines with a hit count > 0
func (lines Lines) NumLinesWithHits() (numLinesWithHits int64) {
for _, line := range lines {
if line.Hits > 0 {
numLinesWithHits++
}
}
return numLinesWithHits
}

// AddOrUpdateLine adds a line if it is a different line than the last line recorded.
// If it's the same line as the last line recorded then we update the hits down
// if the new hits is less; otherwise just leave it as-is
func (lines *Lines) AddOrUpdateLine(lineNumber int, hits int64) {
if len(*lines) > 0 {
lastLine := (*lines)[len(*lines)-1]
if lineNumber == lastLine.Number {
if hits < lastLine.Hits {
lastLine.Hits = hits
}
return
}
}
*lines = append(*lines, &Line{Number: lineNumber, Hits: hits})
}

// HitRate returns a float32 from 0.0 to 1.0 representing what fraction of lines
// have hits
func (method Method) HitRate() float32 {
return method.Lines.HitRate()
}

// NumLines returns the number of lines
func (method Method) NumLines() int64 {
return method.Lines.NumLines()
}

// NumLinesWithHits returns the number of lines with a hit count > 0
func (method Method) NumLinesWithHits() int64 {
return method.Lines.NumLinesWithHits()
}

// HitRate returns a float32 from 0.0 to 1.0 representing what fraction of lines
// have hits
func (class Class) HitRate() float32 {
return float32(class.NumLinesWithHits()) / float32(class.NumLines())
}

// NumLines returns the number of lines
func (class Class) NumLines() (numLines int64) {
for _, method := range class.Methods {
numLines += method.NumLines()
}
return numLines
}

// NumLinesWithHits returns the number of lines with a hit count > 0
func (class Class) NumLinesWithHits() (numLinesWithHits int64) {
for _, method := range class.Methods {
numLinesWithHits += method.NumLinesWithHits()
}
return numLinesWithHits
}

// HitRate returns a float32 from 0.0 to 1.0 representing what fraction of lines
// have hits
func (pkg Package) HitRate() float32 {
return float32(pkg.NumLinesWithHits()) / float32(pkg.NumLines())
}

// NumLines returns the number of lines
func (pkg Package) NumLines() (numLines int64) {
for _, class := range pkg.Classes {
numLines += class.NumLines()
}
return numLines
}

// NumLinesWithHits returns the number of lines with a hit count > 0
func (pkg Package) NumLinesWithHits() (numLinesWithHits int64) {
for _, class := range pkg.Classes {
numLinesWithHits += class.NumLinesWithHits()
}
return numLinesWithHits
}

// HitRate returns a float32 from 0.0 to 1.0 representing what fraction of lines
// have hits
func (cov Coverage) HitRate() float32 {
return float32(cov.NumLinesWithHits()) / float32(cov.NumLines())
}

// NumLines returns the number of lines
func (cov Coverage) NumLines() (numLines int64) {
for _, pkg := range cov.Packages {
numLines += pkg.NumLines()
}
return numLines
}

// NumLinesWithHits returns the number of lines with a hit count > 0
func (cov Coverage) NumLinesWithHits() (numLinesWithHits int64) {
for _, pkg := range cov.Packages {
numLinesWithHits += pkg.NumLinesWithHits()
}
return numLinesWithHits
}
8 changes: 7 additions & 1 deletion gocover-cobertura.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ func (cov *Coverage) parseProfiles(profiles []*Profile) error {
for _, profile := range profiles {
cov.parseProfile(profile)
}
cov.LinesValid = cov.NumLines()
cov.LinesCovered = cov.NumLinesWithHits()
cov.LineRate = cov.HitRate()
return nil
}

Expand Down Expand Up @@ -95,6 +98,7 @@ func (cov *Coverage) parseProfile(profile *Profile) error {
profile: profile,
}
ast.Walk(visitor, parsed)
pkg.LineRate = pkg.HitRate()
return nil
}

Expand All @@ -112,10 +116,12 @@ func (v *fileVisitor) Visit(node ast.Node) ast.Visitor {
case *ast.FuncDecl:
class := v.class(n)
method := v.method(n)
method.LineRate = method.Lines.HitRate()
class.Methods = append(class.Methods, method)
for _, line := range method.Lines {
class.Lines = append(class.Lines, line)
}
class.LineRate = class.Lines.HitRate()
}
return v
}
Expand All @@ -141,7 +147,7 @@ func (v *fileVisitor) method(n *ast.FuncDecl) *Method {
continue
}
for i := b.StartLine; i <= b.EndLine; i++ {
method.Lines = append(method.Lines, &Line{Number: i, Hits: int64(b.Count)})
method.Lines.AddOrUpdateLine(i, int64(b.Count))
}
}
return method
Expand Down
23 changes: 10 additions & 13 deletions gocover-cobertura_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,45 +180,42 @@ func TestConvertSetMode(t *testing.T) {
if c.Methods == nil || len(c.Methods) != 1 {
t.Fatal()
}
if c.Lines == nil || len(c.Lines) != 5 { // Why 5 lines? hmm...
t.Fatal()
if c.Lines == nil || len(c.Lines) != 4 {
t.Errorf("Expected 4 lines but got %d", len(c.Lines))
}

m := c.Methods[0]
if m.Name != "Func1" {
t.Error()
}
if m.Lines == nil || len(m.Lines) != 5 {
t.Fatal()
if c.Lines == nil || len(c.Lines) != 4 {
t.Errorf("Expected 4 lines but got %d", len(c.Lines))
}

var l *Line
if l = m.Lines[0]; l.Number != 4 || l.Hits != 1 {
t.Errorf("unmatched line: Number:%d, Hits:%d", l.Number, l.Hits)
}
if l = m.Lines[1]; l.Number != 5 || l.Hits != 1 {
t.Errorf("unmatched line: Number:%d, Hits:%d", l.Number, l.Hits)
}
if l = m.Lines[2]; l.Number != 5 || l.Hits != 0 {
if l = m.Lines[1]; l.Number != 5 || l.Hits != 0 {
t.Errorf("unmatched line: Number:%d, Hits:%d", l.Number, l.Hits)
}
if l = m.Lines[3]; l.Number != 6 || l.Hits != 0 {
if l = m.Lines[2]; l.Number != 6 || l.Hits != 0 {
t.Errorf("unmatched line: Number:%d, Hits:%d", l.Number, l.Hits)
}
if l = m.Lines[4]; l.Number != 7 || l.Hits != 0 {
if l = m.Lines[3]; l.Number != 7 || l.Hits != 0 {
t.Errorf("unmatched line: Number:%d, Hits:%d", l.Number, l.Hits)
}

if l = c.Lines[0]; l.Number != 4 || l.Hits != 1 {
t.Errorf("unmatched line: Number:%d, Hits:%d", l.Number, l.Hits)
}
if l = c.Lines[1]; l.Number != 5 || l.Hits != 1 {
if l = c.Lines[1]; l.Number != 5 || l.Hits != 0 {
t.Errorf("unmatched line: Number:%d, Hits:%d", l.Number, l.Hits)
}
if l = c.Lines[2]; l.Number != 5 || l.Hits != 0 {
if l = c.Lines[2]; l.Number != 6 || l.Hits != 0 {
t.Errorf("unmatched line: Number:%d, Hits:%d", l.Number, l.Hits)
}
if l = c.Lines[3]; l.Number != 6 || l.Hits != 0 {
if l = c.Lines[3]; l.Number != 7 || l.Hits != 0 {
t.Errorf("unmatched line: Number:%d, Hits:%d", l.Number, l.Hits)
}

Expand Down

0 comments on commit 2dc92ea

Please sign in to comment.