forked from alecthomas/gometalinter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix gotype partition strategy (alecthomas#353)
* Extract issue type into a package It can be re-used by regresiontests Includes some refactoring of regressiontests/support.go Signed-off-by: Daniel Nephin <dnephin@gmail.com> * Fix sorting with multiple keys Signed-off-by: Daniel Nephin <dnephin@gmail.com> * Refactor regressiontests to support testing multiple packages Signed-off-by: Daniel Nephin <dnephin@gmail.com> * Drop issues package Sort issues when running regressiontests Signed-off-by: Daniel Nephin <dnephin@gmail.com> * Fix partition strategy for gotype Also test against multiple packages Signed-off-by: Daniel Nephin <dnephin@gmail.com>
- Loading branch information
1 parent
bfcc1d6
commit 3eeb3c6
Showing
14 changed files
with
257 additions
and
188 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"io/ioutil" | ||
"sort" | ||
"strings" | ||
"text/template" | ||
) | ||
|
||
// DefaultIssueFormat used to print an issue | ||
const DefaultIssueFormat = "{{.Path}}:{{.Line}}:{{if .Col}}{{.Col}}{{end}}:{{.Severity}}: {{.Message}} ({{.Linter}})" | ||
|
||
// Severity of linter message | ||
type Severity string | ||
|
||
// Linter message severity levels. | ||
const ( // nolint: deadcode | ||
Error Severity = "error" | ||
Warning Severity = "warning" | ||
) | ||
|
||
type Issue struct { | ||
Linter string `json:"linter"` | ||
Severity Severity `json:"severity"` | ||
Path string `json:"path"` | ||
Line int `json:"line"` | ||
Col int `json:"col"` | ||
Message string `json:"message"` | ||
formatTmpl *template.Template | ||
} | ||
|
||
// NewIssue returns a new issue. Returns an error if formatTmpl is not a valid | ||
// template for an Issue. | ||
func NewIssue(linter string, formatTmpl *template.Template) (*Issue, error) { | ||
issue := &Issue{ | ||
Line: 1, | ||
Linter: linter, | ||
formatTmpl: formatTmpl, | ||
} | ||
err := formatTmpl.Execute(ioutil.Discard, issue) | ||
return issue, err | ||
} | ||
|
||
func (i *Issue) String() string { | ||
if i.formatTmpl == nil { | ||
col := "" | ||
if i.Col != 0 { | ||
col = fmt.Sprintf("%d", i.Col) | ||
} | ||
return fmt.Sprintf("%s:%d:%s:%s: %s (%s)", strings.TrimSpace(i.Path), i.Line, col, i.Severity, strings.TrimSpace(i.Message), i.Linter) | ||
} | ||
buf := new(bytes.Buffer) | ||
_ = i.formatTmpl.Execute(buf, i) | ||
return buf.String() | ||
} | ||
|
||
type sortedIssues struct { | ||
issues []*Issue | ||
order []string | ||
} | ||
|
||
func (s *sortedIssues) Len() int { return len(s.issues) } | ||
func (s *sortedIssues) Swap(i, j int) { s.issues[i], s.issues[j] = s.issues[j], s.issues[i] } | ||
|
||
func (s *sortedIssues) Less(i, j int) bool { | ||
l, r := s.issues[i], s.issues[j] | ||
return CompareIssue(*l, *r, s.order) | ||
} | ||
|
||
// CompareIssue two Issues and return true if left should sort before right | ||
// nolint: gocyclo | ||
func CompareIssue(l, r Issue, order []string) bool { | ||
for _, key := range order { | ||
switch { | ||
case key == "path" && l.Path != r.Path: | ||
return l.Path < r.Path | ||
case key == "line" && l.Line != r.Line: | ||
return l.Line < r.Line | ||
case key == "column" && l.Col != r.Col: | ||
return l.Col < r.Col | ||
case key == "severity" && l.Severity != r.Severity: | ||
return l.Severity < r.Severity | ||
case key == "message" && l.Message != r.Message: | ||
return l.Message < r.Message | ||
case key == "linter" && l.Linter != r.Linter: | ||
return l.Linter < r.Linter | ||
} | ||
} | ||
return true | ||
} | ||
|
||
// SortIssueChan reads issues from one channel, sorts them, and returns them to another | ||
// channel | ||
func SortIssueChan(issues chan *Issue, order []string) chan *Issue { | ||
out := make(chan *Issue, 1000000) | ||
sorted := &sortedIssues{ | ||
issues: []*Issue{}, | ||
order: order, | ||
} | ||
go func() { | ||
for issue := range issues { | ||
sorted.issues = append(sorted.issues, issue) | ||
} | ||
sort.Sort(sorted) | ||
for _, issue := range sorted.issues { | ||
out <- issue | ||
} | ||
close(out) | ||
}() | ||
return out | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package main | ||
|
||
import ( | ||
"sort" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestSortedIssues(t *testing.T) { | ||
actual := []*Issue{ | ||
{Path: "b.go", Line: 5, Col: 1}, | ||
{Path: "a.go", Line: 3, Col: 2}, | ||
{Path: "b.go", Line: 1, Col: 3}, | ||
{Path: "a.go", Line: 1, Col: 4}, | ||
} | ||
issues := &sortedIssues{ | ||
issues: actual, | ||
order: []string{"path", "line", "column"}, | ||
} | ||
sort.Sort(issues) | ||
expected := []*Issue{ | ||
{Path: "a.go", Line: 1, Col: 4}, | ||
{Path: "a.go", Line: 3, Col: 2}, | ||
{Path: "b.go", Line: 1, Col: 3}, | ||
{Path: "b.go", Line: 5, Col: 1}, | ||
} | ||
require.Equal(t, expected, actual) | ||
} | ||
|
||
func TestCompareOrderWithMessage(t *testing.T) { | ||
order := []string{"path", "line", "column", "message"} | ||
issueM := Issue{Path: "file.go", Message: "message"} | ||
issueU := Issue{Path: "file.go", Message: "unknown"} | ||
|
||
assert.True(t, CompareIssue(issueM, issueU, order)) | ||
assert.False(t, CompareIssue(issueU, issueM, order)) | ||
} |
Oops, something went wrong.