Skip to content

Add support for simplecov's new expected JSON output #441

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Dec 14, 2020
86 changes: 86 additions & 0 deletions formatters/simplecov/json_formatter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package simplecov

import (
"encoding/json"
"os"

"github.com/Sirupsen/logrus"
"github.com/codeclimate/test-reporter/env"
"github.com/codeclimate/test-reporter/formatters"
"github.com/pkg/errors"
)

type branch struct {
Type string `json:"type"`
StartLine int `json:"start_line"`
EndLine int `json:"end_line"`
Coverage interface{} `json:"coverage"`
}

type fileCoverage struct {
LineCoverage []interface{} `json:"lines"`
Branches []branch `json:"branches"`
}

type meta struct {
SimpleCovVersion string `json:"simplecov_version"`
}

type simplecovJsonFormatterReport struct {
Meta meta `json:"meta"`
CoverageType map[string]fileCoverage `json:"coverage"`
}

func transformLineCoverageToCoverage(ln []interface{}) formatters.Coverage {
coverage := make([]formatters.NullInt, len(ln))
ignoredLine := formatters.NullInt{-1, false}
var convertedCoverageValue int
for i := 0; i < len(ln); i++ {
_, ok := ln[i].(string)
if ok {
coverage[i] = ignoredLine
} else {
if ln[i] == nil {
coverage[i] = ignoredLine
} else {
convertedCoverageValue = int(ln[i].(float64))
coverage[i] = formatters.NewNullInt(convertedCoverageValue)
}
}
}

return coverage
}

func jsonFormat(r Formatter, rep formatters.Report) (formatters.Report, error) {
logrus.Debugf("Analyzing simplecov json output from latest format %s", r.Path)
jf, err := os.Open(r.Path)
if err != nil {
return rep, errors.WithStack(errors.Errorf("could not open coverage file %s", r.Path))
}

var m simplecovJsonFormatterReport
decoder := json.NewDecoder(jf)
decoder.DisallowUnknownFields()

err = decoder.Decode(&m)

if err != nil {
return rep, errors.WithStack(err)
}

gitHead, _ := env.GetHead()
for n, ls := range m.CoverageType {
fe, err := formatters.NewSourceFile(n, gitHead)
if err != nil {
return rep, errors.WithStack(err)
}
fe.Coverage = transformLineCoverageToCoverage(ls.LineCoverage)
err = rep.AddSourceFile(fe)
if err != nil {
return rep, errors.WithStack(err)
}
}

return rep, nil
}
47 changes: 47 additions & 0 deletions formatters/simplecov/legacy_formatter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package simplecov

import (
"encoding/json"
"os"

"github.com/Sirupsen/logrus"
"github.com/codeclimate/test-reporter/env"
"github.com/codeclimate/test-reporter/formatters"
"github.com/pkg/errors"
)

type resultSet struct {
Coverage map[string]formatters.Coverage `json:"coverage"`
}

func legacyFormat(r Formatter, rep formatters.Report) (formatters.Report, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we always return rep, can we avoid that and only return error?
And the caller deal with the return it needs to pass? Like return rep, legacyFormat(r, rep)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might not be a go thing, though... let me know.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I liked your suggestion so I tested it out, but for some unknown reason to me tests just started to fail without a clear explanation. Check dacd033 , then I reverted the commit and tests passed again. So ...

logrus.Debugf("Analyzing simplecov json output from legacy format %s", r.Path)
jf, err := os.Open(r.Path)
if err != nil {
return rep, errors.WithStack(errors.Errorf("could not open coverage file %s", r.Path))
}

m := map[string]resultSet{}
err = json.NewDecoder(jf).Decode(&m)

if err != nil {
return rep, errors.WithStack(err)
}

gitHead, _ := env.GetHead()
for _, v := range m {
for n, ls := range v.Coverage {
fe, err := formatters.NewSourceFile(n, gitHead)
if err != nil {
return rep, errors.WithStack(err)
}
fe.Coverage = ls
err = rep.AddSourceFile(fe)
if err != nil {
return rep, errors.WithStack(err)
}
}
}

return rep, nil
}
200 changes: 200 additions & 0 deletions formatters/simplecov/simplecov-branch-example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
{
"meta": {
"simplecov_version": "0.19.0"
},
"coverage": {
"development/mygem/lib/mygem/errors.rb": {
"lines": [
1,
null,
1,
1,
0,
null,
null,
null,
1,
null,
null,
null,
1,
null,
null,
null,
1,
null,
null,
null,
null
],
"branches": [
]
},
"development/mygem/lib/mygem/definition_manager.rb": {
"lines": [
1,
1,
1,
null,
1,
null,
1,
1,
null,
null,
1,
8,
null,
null,
1,
19,
null,
null,
1,
null,
1,
8,
null,
null,
1,
11,
null,
null,
null,
null,
null,
null
],
"branches": [
{
"type": "then",
"start_line": 14,
"end_line": 14,
"coverage": 0
},
{
"type": "else",
"start_line": 16,
"end_line": 16,
"coverage": 1
},
{
"type": "then",
"start_line": 39,
"end_line": 39,
"coverage": 0
},
{
"type": "else",
"start_line": 41,
"end_line": 41,
"coverage": 0
}
]
},
"development/mygem/lib/mygem/interface.rb": {
"lines": [
1,
null,
1,
1,
null,
1,
8,
null,
null,
null,
null
],
"branches": [

]
},
"development/mygem/lib/mygem/implements.rb": {
"lines": [
1,
null,
1,
9,
null,
null,
null
],
"branches": [

]
},
"development/mygem/lib/mygem/implementation_manager.rb": {
"lines": [
1,
1,
1,
null,
1,
null,
1,
1,
null,
null,
1,
9,
null,
null,
1,
82,
null,
null,
1,
null,
1,
9,
null,
null,
1,
73,
null,
null,
null,
null,
null,
null
],
"branches": [

]
},
"development/mygem/lib/mygem/wrap.rb": {
"lines": [
1,
null,
1,
17,
20,
16,
16,
12,
null,
null
],
"branches": [

]
},
"development/mygem/lib/mygem/type_check.rb": {
"lines": [
1,
null,
1,
7,
7,
7,
null,
null,
null
],
"branches": [

]
}
}
}
Loading