From 78d2118c0b119f87e1d72ca2a3b7459ed14d6189 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez <ldez@users.noreply.github.com> Date: Wed, 13 Mar 2024 15:49:29 +0100 Subject: [PATCH] dev: clean up (#4495) --- pkg/config/output.go | 11 +- pkg/config/output_test.go | 15 ++ pkg/result/processors/sort_results.go | 109 ++++++------ pkg/result/processors/sort_results_test.go | 189 ++++++++++++--------- 4 files changed, 187 insertions(+), 137 deletions(-) diff --git a/pkg/config/output.go b/pkg/config/output.go index 9f0ee072..a0734ab7 100644 --- a/pkg/config/output.go +++ b/pkg/config/output.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "slices" + "strings" ) const ( @@ -49,8 +50,16 @@ func (o *Output) Validate() error { return errors.New("sort-results should be 'true' to use sort-order") } + validOrders := []string{"linter", "file", "severity"} + + all := strings.Join(o.SortOrder, " ") + for _, order := range o.SortOrder { - if !slices.Contains([]string{"linter", "file", "severity"}, order) { + if strings.Count(all, order) > 1 { + return fmt.Errorf("the sort-order name %q is repeated several times", order) + } + + if !slices.Contains(validOrders, order) { return fmt.Errorf("unsupported sort-order name %q", order) } } diff --git a/pkg/config/output_test.go b/pkg/config/output_test.go index eb38d27c..93b56ff3 100644 --- a/pkg/config/output_test.go +++ b/pkg/config/output_test.go @@ -32,6 +32,13 @@ func TestOutput_Validate(t *testing.T) { SortOrder: []string{"severity"}, }, }, + { + desc: "multiple", + settings: &Output{ + SortResults: true, + SortOrder: []string{"file", "linter", "severity"}, + }, + }, } for _, test := range testCases { @@ -66,6 +73,14 @@ func TestOutput_Validate_error(t *testing.T) { }, expected: `unsupported sort-order name "a"`, }, + { + desc: "duplicate", + settings: &Output{ + SortResults: true, + SortOrder: []string{"file", "linter", "severity", "linter"}, + }, + expected: `the sort-order name "linter" is repeated several times`, + }, } for _, test := range testCases { diff --git a/pkg/result/processors/sort_results.go b/pkg/result/processors/sort_results.go index 5010fc2c..01ccc994 100644 --- a/pkg/result/processors/sort_results.go +++ b/pkg/result/processors/sort_results.go @@ -17,9 +17,9 @@ import ( // rules that can compare different properties of the Issues struct. const ( - fileOrderName = "file" - linterOrderName = "linter" - linterSeverityName = "severity" + orderNameFile = "file" + orderNameLinter = "linter" + orderNameSeverity = "severity" ) var _ Processor = (*SortResults)(nil) @@ -35,11 +35,11 @@ func NewSortResults(cfg *config.Config) *SortResults { cmps: map[string][]comparator{ // For sorting we are comparing (in next order): // file names, line numbers, position, and finally - giving up. - fileOrderName: {&byName{}, &byLine{}, &byColumn{}}, + orderNameFile: {&byFileName{}, &byLine{}, &byColumn{}}, // For sorting we are comparing: linter name - linterOrderName: {&byLinter{}}, + orderNameLinter: {&byLinter{}}, // For sorting we are comparing: severity - linterSeverityName: {&bySeverity{}}, + orderNameSeverity: {&bySeverity{}}, }, cfg: &cfg.Output, } @@ -52,7 +52,7 @@ func (sr SortResults) Process(issues []result.Issue) ([]result.Issue, error) { } if len(sr.cfg.SortOrder) == 0 { - sr.cfg.SortOrder = []string{fileOrderName} + sr.cfg.SortOrder = []string{orderNameFile} } var cmps []comparator @@ -64,13 +64,13 @@ func (sr SortResults) Process(issues []result.Issue) ([]result.Issue, error) { } } - cmp, err := mergeComparator(cmps) + cmp, err := mergeComparators(cmps) if err != nil { return nil, err } sort.Slice(issues, func(i, j int) bool { - return cmp.Compare(&issues[i], &issues[j]) == Less + return cmp.Compare(&issues[i], &issues[j]) == less }) return issues, nil @@ -83,31 +83,31 @@ func (sr SortResults) Finish() {} type compareResult int const ( - Less compareResult = iota - 1 - Equal - Greater - None + less compareResult = iota - 1 + equal + greater + none ) func (c compareResult) isNeutral() bool { // return true if compare result is incomparable or equal. - return c == None || c == Equal + return c == none || c == equal } func (c compareResult) String() string { switch c { - case Less: - return "Less" - case Equal: - return "Equal" - case Greater: - return "Greater" + case less: + return "less" + case equal: + return "equal" + case greater: + return "greater" default: - return "None" + return "none" } } -// comparator describe how to implement compare for two "issues" lexicographically +// comparator describes how to implement compare for two "issues". type comparator interface { Compare(a, b *result.Issue) compareResult Next() comparator @@ -116,26 +116,25 @@ type comparator interface { } var ( - _ comparator = (*byName)(nil) + _ comparator = (*byFileName)(nil) _ comparator = (*byLine)(nil) _ comparator = (*byColumn)(nil) _ comparator = (*byLinter)(nil) _ comparator = (*bySeverity)(nil) ) -type byName struct{ next comparator } +type byFileName struct{ next comparator } -func (cmp *byName) Next() comparator { return cmp.next } +func (cmp *byFileName) Next() comparator { return cmp.next } -func (cmp *byName) AddNext(c comparator) comparator { +func (cmp *byFileName) AddNext(c comparator) comparator { cmp.next = c return cmp } -func (cmp *byName) Compare(a, b *result.Issue) compareResult { - var res compareResult - - if res = compareResult(strings.Compare(a.FilePath(), b.FilePath())); !res.isNeutral() { +func (cmp *byFileName) Compare(a, b *result.Issue) compareResult { + res := compareResult(strings.Compare(a.FilePath(), b.FilePath())) + if !res.isNeutral() { return res } @@ -146,8 +145,8 @@ func (cmp *byName) Compare(a, b *result.Issue) compareResult { return res } -func (cmp *byName) String() string { - return comparatorToString("byName", cmp) +func (cmp *byFileName) String() string { + return comparatorToString("byFileName", cmp) } type byLine struct{ next comparator } @@ -160,9 +159,8 @@ func (cmp *byLine) AddNext(c comparator) comparator { } func (cmp *byLine) Compare(a, b *result.Issue) compareResult { - var res compareResult - - if res = numericCompare(a.Line(), b.Line()); !res.isNeutral() { + res := numericCompare(a.Line(), b.Line()) + if !res.isNeutral() { return res } @@ -187,9 +185,8 @@ func (cmp *byColumn) AddNext(c comparator) comparator { } func (cmp *byColumn) Compare(a, b *result.Issue) compareResult { - var res compareResult - - if res = numericCompare(a.Column(), b.Column()); !res.isNeutral() { + res := numericCompare(a.Column(), b.Column()) + if !res.isNeutral() { return res } @@ -214,9 +211,8 @@ func (cmp *byLinter) AddNext(c comparator) comparator { } func (cmp *byLinter) Compare(a, b *result.Issue) compareResult { - var res compareResult - - if res = compareResult(strings.Compare(a.FromLinter, b.FromLinter)); !res.isNeutral() { + res := compareResult(strings.Compare(a.FromLinter, b.FromLinter)) + if !res.isNeutral() { return res } @@ -241,9 +237,8 @@ func (cmp *bySeverity) AddNext(c comparator) comparator { } func (cmp *bySeverity) Compare(a, b *result.Issue) compareResult { - var res compareResult - - if res = severityCompare(a.Severity, b.Severity); !res.isNeutral() { + res := severityCompare(a.Severity, b.Severity) + if !res.isNeutral() { return res } @@ -258,7 +253,7 @@ func (cmp *bySeverity) String() string { return comparatorToString("bySeverity", cmp) } -func mergeComparator(cmps []comparator) (comparator, error) { +func mergeComparators(cmps []comparator) (comparator, error) { if len(cmps) == 0 { return nil, errors.New("no comparator") } @@ -277,14 +272,22 @@ func severityCompare(a, b string) compareResult { if slices.Contains(classic, a) && slices.Contains(classic, b) { switch { case slices.Index(classic, a) > slices.Index(classic, b): - return Greater + return greater case slices.Index(classic, a) < slices.Index(classic, b): - return Less + return less default: - return Equal + return equal } } + if slices.Contains(classic, a) { + return greater + } + + if slices.Contains(classic, b) { + return less + } + return compareResult(strings.Compare(a, b)) } @@ -299,16 +302,16 @@ func numericCompare(a, b int) compareResult { switch { case isZeroValuesBoth || isEqual: - return Equal + return equal case isValuesInvalid || isZeroValueInA || isZeroValueInB: - return None + return none case a > b: - return Greater + return greater case a < b: - return Less + return less } - return Equal + return equal } func comparatorToString(name string, c comparator) string { diff --git a/pkg/result/processors/sort_results_test.go b/pkg/result/processors/sort_results_test.go index b0d0043f..ef73d5bb 100644 --- a/pkg/result/processors/sort_results_test.go +++ b/pkg/result/processors/sort_results_test.go @@ -50,6 +50,27 @@ var issues = []result.Issue{ }, } +var extraSeverityIssues = []result.Issue{ + { + FromLinter: "c", + Severity: "error", + Pos: token.Position{ + Filename: "file_darwin.go", + Column: 60, + Line: 10, + }, + }, + { + FromLinter: "c", + Severity: "aaaa", + Pos: token.Position{ + Filename: "file_darwin.go", + Column: 60, + Line: 10, + }, + }, +} + type compareTestCase struct { a, b result.Issue expected compareResult @@ -69,98 +90,100 @@ func testCompareValues(t *testing.T, cmp comparator, name string, tests []compar func TestCompareByLine(t *testing.T) { testCompareValues(t, &byLine{}, "Compare By Line", []compareTestCase{ - {issues[0], issues[1], Less}, // 10 vs 11 - {issues[0], issues[0], Equal}, // 10 vs 10 - {issues[3], issues[3], Equal}, // 10 vs 10 - {issues[0], issues[3], Equal}, // 10 vs 10 - {issues[3], issues[2], Less}, // 10 vs 12 - {issues[1], issues[1], Equal}, // 11 vs 11 - {issues[1], issues[0], Greater}, // 11 vs 10 - {issues[1], issues[2], Less}, // 11 vs 12 - {issues[2], issues[3], Greater}, // 12 vs 10 - {issues[2], issues[1], Greater}, // 12 vs 11 - {issues[2], issues[2], Equal}, // 12 vs 12 + {issues[0], issues[1], less}, // 10 vs 11 + {issues[0], issues[0], equal}, // 10 vs 10 + {issues[3], issues[3], equal}, // 10 vs 10 + {issues[0], issues[3], equal}, // 10 vs 10 + {issues[3], issues[2], less}, // 10 vs 12 + {issues[1], issues[1], equal}, // 11 vs 11 + {issues[1], issues[0], greater}, // 11 vs 10 + {issues[1], issues[2], less}, // 11 vs 12 + {issues[2], issues[3], greater}, // 12 vs 10 + {issues[2], issues[1], greater}, // 12 vs 11 + {issues[2], issues[2], equal}, // 12 vs 12 }) } -func TestCompareByName(t *testing.T) { //nolint:dupl - testCompareValues(t, &byName{}, "Compare By Name", []compareTestCase{ - {issues[0], issues[1], Greater}, // file_windows.go vs file_linux.go - {issues[1], issues[2], Greater}, // file_linux.go vs file_darwin.go - {issues[2], issues[3], Equal}, // file_darwin.go vs file_darwin.go - {issues[1], issues[1], Equal}, // file_linux.go vs file_linux.go - {issues[1], issues[0], Less}, // file_linux.go vs file_windows.go - {issues[3], issues[2], Equal}, // file_darwin.go vs file_darwin.go - {issues[2], issues[1], Less}, // file_darwin.go vs file_linux.go - {issues[0], issues[0], Equal}, // file_windows.go vs file_windows.go - {issues[2], issues[2], Equal}, // file_darwin.go vs file_darwin.go - {issues[3], issues[3], Equal}, // file_darwin.go vs file_darwin.go +func TestCompareByFileName(t *testing.T) { //nolint:dupl + testCompareValues(t, &byFileName{}, "Compare By File Name", []compareTestCase{ + {issues[0], issues[1], greater}, // file_windows.go vs file_linux.go + {issues[1], issues[2], greater}, // file_linux.go vs file_darwin.go + {issues[2], issues[3], equal}, // file_darwin.go vs file_darwin.go + {issues[1], issues[1], equal}, // file_linux.go vs file_linux.go + {issues[1], issues[0], less}, // file_linux.go vs file_windows.go + {issues[3], issues[2], equal}, // file_darwin.go vs file_darwin.go + {issues[2], issues[1], less}, // file_darwin.go vs file_linux.go + {issues[0], issues[0], equal}, // file_windows.go vs file_windows.go + {issues[2], issues[2], equal}, // file_darwin.go vs file_darwin.go + {issues[3], issues[3], equal}, // file_darwin.go vs file_darwin.go }) } func TestCompareByColumn(t *testing.T) { //nolint:dupl testCompareValues(t, &byColumn{}, "Compare By Column", []compareTestCase{ - {issues[0], issues[1], Greater}, // 80 vs 70 - {issues[1], issues[2], None}, // 70 vs zero value - {issues[3], issues[3], Equal}, // 60 vs 60 - {issues[2], issues[3], None}, // zero value vs 60 - {issues[2], issues[1], None}, // zero value vs 70 - {issues[1], issues[0], Less}, // 70 vs 80 - {issues[1], issues[1], Equal}, // 70 vs 70 - {issues[3], issues[2], None}, // vs zero value - {issues[2], issues[2], Equal}, // zero value vs zero value - {issues[1], issues[1], Equal}, // 70 vs 70 + {issues[0], issues[1], greater}, // 80 vs 70 + {issues[1], issues[2], none}, // 70 vs zero value + {issues[3], issues[3], equal}, // 60 vs 60 + {issues[2], issues[3], none}, // zero value vs 60 + {issues[2], issues[1], none}, // zero value vs 70 + {issues[1], issues[0], less}, // 70 vs 80 + {issues[1], issues[1], equal}, // 70 vs 70 + {issues[3], issues[2], none}, // vs zero value + {issues[2], issues[2], equal}, // zero value vs zero value + {issues[1], issues[1], equal}, // 70 vs 70 }) } func TestCompareByLinter(t *testing.T) { //nolint:dupl testCompareValues(t, &byLinter{}, "Compare By Linter", []compareTestCase{ - {issues[0], issues[1], Greater}, // b vs a - {issues[1], issues[2], Less}, // a vs c - {issues[2], issues[3], Equal}, // c vs c - {issues[1], issues[1], Equal}, // a vs a - {issues[1], issues[0], Less}, // a vs b - {issues[3], issues[2], Equal}, // c vs c - {issues[2], issues[1], Greater}, // c vs a - {issues[0], issues[0], Equal}, // b vs b - {issues[2], issues[2], Equal}, // a vs a - {issues[3], issues[3], Equal}, // c vs c + {issues[0], issues[1], greater}, // b vs a + {issues[1], issues[2], less}, // a vs c + {issues[2], issues[3], equal}, // c vs c + {issues[1], issues[1], equal}, // a vs a + {issues[1], issues[0], less}, // a vs b + {issues[3], issues[2], equal}, // c vs c + {issues[2], issues[1], greater}, // c vs a + {issues[0], issues[0], equal}, // b vs b + {issues[2], issues[2], equal}, // a vs a + {issues[3], issues[3], equal}, // c vs c }) } -func TestCompareBySeverity(t *testing.T) { //nolint:dupl +func TestCompareBySeverity(t *testing.T) { testCompareValues(t, &bySeverity{}, "Compare By Severity", []compareTestCase{ - {issues[0], issues[1], Greater}, // medium vs low - {issues[1], issues[2], Less}, // low vs high - {issues[2], issues[3], Equal}, // high vs high - {issues[1], issues[1], Equal}, // low vs low - {issues[1], issues[0], Less}, // low vs medium - {issues[3], issues[2], Equal}, // high vs high - {issues[2], issues[1], Greater}, // high vs low - {issues[0], issues[0], Equal}, // medium vs medium - {issues[2], issues[2], Equal}, // low vs low - {issues[3], issues[3], Equal}, // high vs high + {issues[0], issues[1], greater}, // medium vs low + {issues[1], issues[2], less}, // low vs high + {issues[2], issues[3], equal}, // high vs high + {issues[1], issues[1], equal}, // low vs low + {issues[1], issues[0], less}, // low vs medium + {issues[3], issues[2], equal}, // high vs high + {issues[2], issues[1], greater}, // high vs low + {issues[0], issues[0], equal}, // medium vs medium + {issues[2], issues[2], equal}, // low vs low + {issues[3], issues[3], equal}, // high vs high + {extraSeverityIssues[0], extraSeverityIssues[1], greater}, // classic vs unknown + {extraSeverityIssues[1], extraSeverityIssues[0], less}, // unknown vs classic }) } func TestCompareNested(t *testing.T) { - var cmp = &byName{ + var cmp = &byFileName{ next: &byLine{ next: &byColumn{}, }, } testCompareValues(t, cmp, "Nested Comparing", []compareTestCase{ - {issues[1], issues[0], Less}, // file_linux.go vs file_windows.go - {issues[2], issues[1], Less}, // file_darwin.go vs file_linux.go - {issues[0], issues[1], Greater}, // file_windows.go vs file_linux.go - {issues[1], issues[2], Greater}, // file_linux.go vs file_darwin.go - {issues[3], issues[2], Less}, // file_darwin.go vs file_darwin.go, 10 vs 12 - {issues[0], issues[0], Equal}, // file_windows.go vs file_windows.go - {issues[2], issues[3], Greater}, // file_darwin.go vs file_darwin.go, 12 vs 10 - {issues[1], issues[1], Equal}, // file_linux.go vs file_linux.go - {issues[2], issues[2], Equal}, // file_darwin.go vs file_darwin.go - {issues[3], issues[3], Equal}, // file_darwin.go vs file_darwin.go + {issues[1], issues[0], less}, // file_linux.go vs file_windows.go + {issues[2], issues[1], less}, // file_darwin.go vs file_linux.go + {issues[0], issues[1], greater}, // file_windows.go vs file_linux.go + {issues[1], issues[2], greater}, // file_linux.go vs file_darwin.go + {issues[3], issues[2], less}, // file_darwin.go vs file_darwin.go, 10 vs 12 + {issues[0], issues[0], equal}, // file_windows.go vs file_windows.go + {issues[2], issues[3], greater}, // file_darwin.go vs file_darwin.go, 12 vs 10 + {issues[1], issues[1], equal}, // file_linux.go vs file_linux.go + {issues[2], issues[2], equal}, // file_darwin.go vs file_darwin.go + {issues[3], issues[3], equal}, // file_darwin.go vs file_darwin.go }) } @@ -169,14 +192,14 @@ func TestNumericCompare(t *testing.T) { a, b int expected compareResult }{ - {0, 0, Equal}, - {0, 1, None}, - {1, 0, None}, - {1, -1, None}, - {-1, 1, None}, - {1, 1, Equal}, - {1, 2, Less}, - {2, 1, Greater}, + {0, 0, equal}, + {0, 1, none}, + {1, 0, none}, + {1, -1, none}, + {-1, 1, none}, + {1, 1, equal}, + {1, 2, less}, + {2, 1, greater}, } t.Parallel() @@ -214,7 +237,7 @@ func TestSorting(t *testing.T) { assert.Equal(t, []result.Issue{issues[3], issues[2], issues[1], issues[0]}, results) } -func Test_mergeComparator(t *testing.T) { +func Test_mergeComparators(t *testing.T) { testCases := []struct { desc string cmps []comparator @@ -227,18 +250,18 @@ func Test_mergeComparator(t *testing.T) { }, { desc: "two", - cmps: []comparator{&byLinter{}, &byName{}}, - expected: "byLinter > byName", + cmps: []comparator{&byLinter{}, &byFileName{}}, + expected: "byLinter > byFileName", }, { desc: "all", - cmps: []comparator{&bySeverity{}, &byLinter{}, &byName{}, &byLine{}, &byColumn{}}, - expected: "bySeverity > byLinter > byName > byLine > byColumn", + cmps: []comparator{&bySeverity{}, &byLinter{}, &byFileName{}, &byLine{}, &byColumn{}}, + expected: "bySeverity > byLinter > byFileName > byLine > byColumn", }, { desc: "all reverse", - cmps: []comparator{&byColumn{}, &byLine{}, &byName{}, &byLinter{}, &bySeverity{}}, - expected: "byColumn > byLine > byName > byLinter > bySeverity", + cmps: []comparator{&byColumn{}, &byLine{}, &byFileName{}, &byLinter{}, &bySeverity{}}, + expected: "byColumn > byLine > byFileName > byLinter > bySeverity", }, } @@ -247,7 +270,7 @@ func Test_mergeComparator(t *testing.T) { t.Run(test.desc, func(t *testing.T) { t.Parallel() - cmp, err := mergeComparator(test.cmps) + cmp, err := mergeComparators(test.cmps) require.NoError(t, err) assert.Equal(t, test.expected, cmp.String()) @@ -255,7 +278,7 @@ func Test_mergeComparator(t *testing.T) { } } -func Test_mergeComparator_error(t *testing.T) { - _, err := mergeComparator(nil) +func Test_mergeComparators_error(t *testing.T) { + _, err := mergeComparators(nil) require.EqualError(t, err, "no comparator") }