dev: review and clean linter tests (#3139)

This commit is contained in:
Ludovic Fernandez 2022-09-01 18:26:28 +02:00 committed by GitHub
parent aba80c7fe2
commit 39f401ba3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 203 additions and 205 deletions

View File

@ -136,7 +136,6 @@ issues:
- path: pkg/lint/lintersdb/manager.go - path: pkg/lint/lintersdb/manager.go
text: "SA1019: (.+).(GoVersion|LangVersion) is deprecated: use the global `run.go` instead." text: "SA1019: (.+).(GoVersion|LangVersion) is deprecated: use the global `run.go` instead."
run: run:
timeout: 5m timeout: 5m
go: '1.17' # TODO(ldez): we force to use an old version of Go for the CI and the tests. go: '1.17' # TODO(ldez): we force to use an old version of Go for the CI and the tests.

View File

@ -90,10 +90,8 @@ var (
type ByName struct{ next comparator } type ByName struct{ next comparator }
//nolint:golint
func (cmp ByName) Next() comparator { return cmp.next } func (cmp ByName) Next() comparator { return cmp.next }
//nolint:golint
func (cmp ByName) Compare(a, b *result.Issue) compareResult { func (cmp ByName) Compare(a, b *result.Issue) compareResult {
var res compareResult var res compareResult
@ -110,10 +108,8 @@ func (cmp ByName) Compare(a, b *result.Issue) compareResult {
type ByLine struct{ next comparator } type ByLine struct{ next comparator }
//nolint:golint
func (cmp ByLine) Next() comparator { return cmp.next } func (cmp ByLine) Next() comparator { return cmp.next }
//nolint:golint
func (cmp ByLine) Compare(a, b *result.Issue) compareResult { func (cmp ByLine) Compare(a, b *result.Issue) compareResult {
var res compareResult var res compareResult
@ -130,10 +126,8 @@ func (cmp ByLine) Compare(a, b *result.Issue) compareResult {
type ByColumn struct{ next comparator } type ByColumn struct{ next comparator }
//nolint:golint
func (cmp ByColumn) Next() comparator { return cmp.next } func (cmp ByColumn) Next() comparator { return cmp.next }
//nolint:golint
func (cmp ByColumn) Compare(a, b *result.Issue) compareResult { func (cmp ByColumn) Compare(a, b *result.Issue) compareResult {
var res compareResult var res compareResult

View File

@ -10,72 +10,11 @@ import (
"github.com/golangci/golangci-lint/test/testshared" "github.com/golangci/golangci-lint/test/testshared"
) )
func inSlice(s []string, v string) bool {
for _, sv := range s {
if sv == v {
return true
}
}
return false
}
func getEnabledByDefaultFastLintersExcept(except ...string) []string {
m := lintersdb.NewManager(nil, nil)
ebdl := m.GetAllEnabledByDefaultLinters()
var ret []string
for _, lc := range ebdl {
if lc.IsSlowLinter() {
continue
}
if !inSlice(except, lc.Name()) {
ret = append(ret, lc.Name())
}
}
return ret
}
func getAllFastLintersWith(with ...string) []string {
linters := lintersdb.NewManager(nil, nil).GetAllSupportedLinterConfigs()
ret := append([]string{}, with...)
for _, lc := range linters {
if lc.IsSlowLinter() {
continue
}
ret = append(ret, lc.Name())
}
return ret
}
func getEnabledByDefaultLinters() []string {
ebdl := lintersdb.NewManager(nil, nil).GetAllEnabledByDefaultLinters()
var ret []string
for _, lc := range ebdl {
ret = append(ret, lc.Name())
}
return ret
}
func getEnabledByDefaultFastLintersWith(with ...string) []string {
ebdl := lintersdb.NewManager(nil, nil).GetAllEnabledByDefaultLinters()
ret := append([]string{}, with...)
for _, lc := range ebdl {
if lc.IsSlowLinter() {
continue
}
ret = append(ret, lc.Name())
}
return ret
}
//nolint:funlen //nolint:funlen
func TestEnabledLinters(t *testing.T) { func TestEnabledLinters(t *testing.T) {
// require to display the message "Active x linters: [x,y]"
t.Setenv("GL_TEST_RUN", "1")
cases := []struct { cases := []struct {
name string name string
cfg string cfg string
@ -93,13 +32,13 @@ func TestEnabledLinters(t *testing.T) {
enabledLinters: getEnabledByDefaultFastLintersExcept("govet"), enabledLinters: getEnabledByDefaultFastLintersExcept("govet"),
}, },
{ {
name: "enable golint in config", name: "enable revive in config",
cfg: ` cfg: `
linters: linters:
enable: enable:
- golint - revive
`, `,
enabledLinters: getEnabledByDefaultFastLintersWith("golint"), enabledLinters: getEnabledByDefaultFastLintersWith("revive"),
}, },
{ {
name: "disable govet in cmd", name: "disable govet in cmd",
@ -107,14 +46,14 @@ func TestEnabledLinters(t *testing.T) {
enabledLinters: getEnabledByDefaultFastLintersExcept("govet"), enabledLinters: getEnabledByDefaultFastLintersExcept("govet"),
}, },
{ {
name: "enable gofmt in cmd and enable golint in config", name: "enable gofmt in cmd and enable revive in config",
args: []string{"-Egofmt"}, args: []string{"-Egofmt"},
cfg: ` cfg: `
linters: linters:
enable: enable:
- golint - revive
`, `,
enabledLinters: getEnabledByDefaultFastLintersWith("golint", "gofmt"), enabledLinters: getEnabledByDefaultFastLintersWith("revive", "gofmt"),
}, },
{ {
name: "fast option in config", name: "fast option in config",
@ -195,3 +134,67 @@ func TestEnabledLinters(t *testing.T) {
}) })
} }
} }
func inSlice(s []string, v string) bool {
for _, sv := range s {
if sv == v {
return true
}
}
return false
}
func getEnabledByDefaultFastLintersExcept(except ...string) []string {
m := lintersdb.NewManager(nil, nil)
ebdl := m.GetAllEnabledByDefaultLinters()
var ret []string
for _, lc := range ebdl {
if lc.IsSlowLinter() {
continue
}
if !inSlice(except, lc.Name()) {
ret = append(ret, lc.Name())
}
}
return ret
}
func getAllFastLintersWith(with ...string) []string {
linters := lintersdb.NewManager(nil, nil).GetAllSupportedLinterConfigs()
ret := append([]string{}, with...)
for _, lc := range linters {
if lc.IsSlowLinter() {
continue
}
ret = append(ret, lc.Name())
}
return ret
}
func getEnabledByDefaultLinters() []string {
ebdl := lintersdb.NewManager(nil, nil).GetAllEnabledByDefaultLinters()
var ret []string
for _, lc := range ebdl {
ret = append(ret, lc.Name())
}
return ret
}
func getEnabledByDefaultFastLintersWith(with ...string) []string {
ebdl := lintersdb.NewManager(nil, nil).GetAllEnabledByDefaultLinters()
ret := append([]string{}, with...)
for _, lc := range ebdl {
if lc.IsSlowLinter() {
continue
}
ret = append(ret, lc.Name())
}
return ret
}

View File

@ -2,7 +2,6 @@ package test
import ( import (
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -14,8 +13,6 @@ import (
const minimalPkg = "minimalpkg" const minimalPkg = "minimalpkg"
const skipDirsCommand = "testdata_etc/,pkg/golinters/goanalysis/(checker|passes)"
func TestAutogeneratedNoIssues(t *testing.T) { func TestAutogeneratedNoIssues(t *testing.T) {
testshared.NewRunnerBuilder(t). testshared.NewRunnerBuilder(t).
WithTargetPath(testdataDir, "autogenerated"). WithTargetPath(testdataDir, "autogenerated").
@ -85,11 +82,9 @@ func TestTimeout(t *testing.T) {
} }
func TestTimeoutInConfig(t *testing.T) { func TestTimeoutInConfig(t *testing.T) {
type tc struct { cases := []struct {
cfg string cfg string
} }{
cases := []tc{
{ {
cfg: ` cfg: `
run: run:
@ -118,7 +113,6 @@ func TestTimeoutInConfig(t *testing.T) {
// Run with disallowed option set only in config // Run with disallowed option set only in config
testshared.NewRunnerBuilder(t). testshared.NewRunnerBuilder(t).
WithConfig(c.cfg). WithConfig(c.cfg).
WithArgs("--skip-dirs", skipDirsCommand).
WithTargetPath(testdataDir, minimalPkg). WithTargetPath(testdataDir, minimalPkg).
Runner(). Runner().
Run(). Run().
@ -202,104 +196,8 @@ func TestCgoWithIssues(t *testing.T) {
} }
} }
func TestUnsafeOk(t *testing.T) { // https://pkg.go.dev/cmd/compile#hdr-Compiler_Directives
testshared.NewRunnerBuilder(t). func TestLineDirective(t *testing.T) {
WithNoConfig().
WithArgs("--enable-all").
WithTargetPath(testdataDir, "unsafe").
Runner().
Install().
Run().
ExpectNoIssues()
}
func TestGovetCustomFormatter(t *testing.T) {
testshared.NewRunnerBuilder(t).
WithTargetPath(testdataDir, "govet_custom_formatter").
Runner().
Install().
Run().
ExpectNoIssues()
}
func TestLineDirectiveProcessedFilesLiteLoading(t *testing.T) {
output := strings.Join([]string{
"testdata/quicktemplate/hello.qtpl.go:26:1: exported function `StreamHello` should have comment or be unexported (golint)",
"testdata/quicktemplate/hello.qtpl.go:50:1: exported function `Hello` should have comment or be unexported (golint)",
"testdata/quicktemplate/hello.qtpl.go:39:1: exported function `WriteHello` should have comment or be unexported (golint)",
}, "\n")
testshared.NewRunnerBuilder(t).
WithNoConfig().
WithArgs(
"--print-issued-lines=false",
"--exclude-use-default=false",
"-Egolint",
).
WithTargetPath(testdataDir, "quicktemplate").
Runner().
Install().
Run().
ExpectExitCode(exitcodes.IssuesFound).ExpectOutputEq(output + "\n")
}
func TestSortedResults(t *testing.T) {
testCases := []struct {
opt string
want string
}{
{
opt: "--sort-results=false",
want: "testdata/sort_results/main.go:15:13: Error return value is not checked (errcheck)" + "\n" +
"testdata/sort_results/main.go:12:5: var `db` is unused (unused)",
},
{
opt: "--sort-results=true",
want: "testdata/sort_results/main.go:12:5: var `db` is unused (unused)" + "\n" +
"testdata/sort_results/main.go:15:13: Error return value is not checked (errcheck)",
},
}
testshared.InstallGolangciLint(t)
for _, test := range testCases {
test := test
t.Run(test.opt, func(t *testing.T) {
t.Parallel()
testshared.NewRunnerBuilder(t).
WithNoConfig().
WithArgs("--print-issued-lines=false", test.opt).
WithTargetPath(testdataDir, "sort_results").
Runner().
Run().
ExpectExitCode(exitcodes.IssuesFound).ExpectOutputEq(test.want + "\n")
})
}
}
func TestLineDirectiveProcessedFilesFullLoading(t *testing.T) {
output := strings.Join([]string{
"testdata/quicktemplate/hello.qtpl.go:26:1: exported function `StreamHello` should have comment or be unexported (golint)",
"testdata/quicktemplate/hello.qtpl.go:50:1: exported function `Hello` should have comment or be unexported (golint)",
"testdata/quicktemplate/hello.qtpl.go:39:1: exported function `WriteHello` should have comment or be unexported (golint)",
}, "\n")
testshared.NewRunnerBuilder(t).
WithNoConfig().
WithArgs(
"--print-issued-lines=false",
"--exclude-use-default=false",
"-Egolint,govet",
).
WithTargetPath(testdataDir, "quicktemplate").
Runner().
Install().
Run().
ExpectExitCode(exitcodes.IssuesFound).ExpectOutputEq(output + "\n")
}
func TestLintFilesWithLineDirective(t *testing.T) {
testshared.InstallGolangciLint(t) testshared.InstallGolangciLint(t)
testCases := []struct { testCases := []struct {
@ -396,6 +294,110 @@ func TestLintFilesWithLineDirective(t *testing.T) {
} }
} }
// https://pkg.go.dev/cmd/compile#hdr-Compiler_Directives
func TestLineDirectiveProcessedFiles(t *testing.T) {
testCases := []struct {
desc string
args []string
target string
expected []string
}{
{
desc: "lite loading",
args: []string{
"--print-issued-lines=false",
"--exclude-use-default=false",
"-Erevive",
},
target: "quicktemplate",
expected: []string{
"testdata/quicktemplate/hello.qtpl.go:10:1: package-comments: should have a package comment (revive)",
"testdata/quicktemplate/hello.qtpl.go:26:1: exported: exported function StreamHello should have comment or be unexported (revive)",
"testdata/quicktemplate/hello.qtpl.go:39:1: exported: exported function WriteHello should have comment or be unexported (revive)",
"testdata/quicktemplate/hello.qtpl.go:50:1: exported: exported function Hello should have comment or be unexported (revive)",
},
},
{
desc: "full loading",
args: []string{
"--print-issued-lines=false",
"--exclude-use-default=false",
"-Erevive,govet",
},
target: "quicktemplate",
expected: []string{
"testdata/quicktemplate/hello.qtpl.go:10:1: package-comments: should have a package comment (revive)",
"testdata/quicktemplate/hello.qtpl.go:26:1: exported: exported function StreamHello should have comment or be unexported (revive)",
"testdata/quicktemplate/hello.qtpl.go:39:1: exported: exported function WriteHello should have comment or be unexported (revive)",
"testdata/quicktemplate/hello.qtpl.go:50:1: exported: exported function Hello should have comment or be unexported (revive)",
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
testshared.NewRunnerBuilder(t).
WithNoConfig().
WithArgs(test.args...).
WithTargetPath(testdataDir, test.target).
Runner().
Install().
Run().
ExpectExitCode(exitcodes.IssuesFound).
ExpectOutputContains(test.expected...)
})
}
}
func TestUnsafeOk(t *testing.T) {
testshared.NewRunnerBuilder(t).
WithNoConfig().
WithArgs("--enable-all").
WithTargetPath(testdataDir, "unsafe").
Runner().
Install().
Run().
ExpectNoIssues()
}
func TestSortedResults(t *testing.T) {
testCases := []struct {
opt string
want string
}{
{
opt: "--sort-results=false",
want: "testdata/sort_results/main.go:15:13: Error return value is not checked (errcheck)" + "\n" +
"testdata/sort_results/main.go:12:5: var `db` is unused (unused)",
},
{
opt: "--sort-results=true",
want: "testdata/sort_results/main.go:12:5: var `db` is unused (unused)" + "\n" +
"testdata/sort_results/main.go:15:13: Error return value is not checked (errcheck)",
},
}
testshared.InstallGolangciLint(t)
for _, test := range testCases {
test := test
t.Run(test.opt, func(t *testing.T) {
t.Parallel()
testshared.NewRunnerBuilder(t).
WithNoConfig().
WithArgs("--print-issued-lines=false", test.opt).
WithTargetPath(testdataDir, "sort_results").
Runner().
Run().
ExpectExitCode(exitcodes.IssuesFound).ExpectOutputEq(test.want + "\n")
})
}
}
func TestSkippedDirsNoMatchArg(t *testing.T) { func TestSkippedDirsNoMatchArg(t *testing.T) {
dir := filepath.Join(testdataDir, "skipdirs", "skip_me", "nested") dir := filepath.Join(testdataDir, "skipdirs", "skip_me", "nested")
@ -404,15 +406,15 @@ func TestSkippedDirsNoMatchArg(t *testing.T) {
WithArgs( WithArgs(
"--print-issued-lines=false", "--print-issued-lines=false",
"--skip-dirs", dir, "--skip-dirs", dir,
"-Egolint", "-Erevive",
). ).
WithTargetPath(dir). WithTargetPath(dir).
Runner(). Runner().
Install(). Install().
Run(). Run().
ExpectExitCode(exitcodes.IssuesFound). ExpectExitCode(exitcodes.IssuesFound).
ExpectOutputEq("testdata/skipdirs/skip_me/nested/with_issue.go:8:9: `if` block ends with " + ExpectOutputEq("testdata/skipdirs/skip_me/nested/with_issue.go:8:9: " +
"a `return` statement, so drop this `else` and outdent its block (golint)\n") "indent-error-flow: if block ends with a return statement, so drop this else and outdent its block (revive)\n")
} }
func TestSkippedDirsTestdata(t *testing.T) { func TestSkippedDirsTestdata(t *testing.T) {
@ -420,7 +422,7 @@ func TestSkippedDirsTestdata(t *testing.T) {
WithNoConfig(). WithNoConfig().
WithArgs( WithArgs(
"--print-issued-lines=false", "--print-issued-lines=false",
"-Egolint", "-Erevive",
). ).
WithTargetPath(testdataDir, "skipdirs", "..."). WithTargetPath(testdataDir, "skipdirs", "...").
Runner(). Runner().
@ -511,7 +513,6 @@ func TestEnableAllFastAndEnableCanCoexist(t *testing.T) {
testshared.NewRunnerBuilder(t). testshared.NewRunnerBuilder(t).
WithNoConfig(). WithNoConfig().
WithArgs("--skip-dirs", skipDirsCommand).
WithArgs(test.args...). WithArgs(test.args...).
WithTargetPath(testdataDir, minimalPkg). WithTargetPath(testdataDir, minimalPkg).
Runner(). Runner().
@ -541,13 +542,14 @@ func TestAbsPathDirAnalysis(t *testing.T) {
WithNoConfig(). WithNoConfig().
WithArgs( WithArgs(
"--print-issued-lines=false", "--print-issued-lines=false",
"-Egolint", "-Erevive",
). ).
WithTargetPath(absDir). WithTargetPath(absDir).
Runner(). Runner().
Install(). Install().
Run(). Run().
ExpectHasIssue("`if` block ends with a `return` statement") ExpectHasIssue("testdata_etc/abspath/with_issue.go:8:9: " +
"indent-error-flow: if block ends with a return statement, so drop this else and outdent its block (revive)")
} }
func TestAbsPathFileAnalysis(t *testing.T) { func TestAbsPathFileAnalysis(t *testing.T) {
@ -559,22 +561,20 @@ func TestAbsPathFileAnalysis(t *testing.T) {
WithNoConfig(). WithNoConfig().
WithArgs( WithArgs(
"--print-issued-lines=false", "--print-issued-lines=false",
"-Egolint", "-Erevive",
). ).
WithTargetPath(absDir). WithTargetPath(absDir).
Runner(). Runner().
Install(). Install().
Run(). Run().
ExpectHasIssue("`if` block ends with a `return` statement") ExpectHasIssue("indent-error-flow: if block ends with a return statement, so drop this else and outdent its block (revive)")
} }
func TestDisallowedOptionsInConfig(t *testing.T) { func TestDisallowedOptionsInConfig(t *testing.T) {
type tc struct { cases := []struct {
cfg string cfg string
option string option string
} }{
cases := []tc{
{ {
cfg: ` cfg: `
ruN: ruN:
@ -618,7 +618,6 @@ func TestDisallowedOptionsInConfig(t *testing.T) {
// Run with disallowed option set only in config // Run with disallowed option set only in config
testshared.NewRunnerBuilder(t). testshared.NewRunnerBuilder(t).
WithConfig(c.cfg). WithConfig(c.cfg).
WithArgs("--skip-dirs", skipDirsCommand).
WithTargetPath(testdataDir, minimalPkg). WithTargetPath(testdataDir, minimalPkg).
Runner(). Runner().
Run(). Run().
@ -633,7 +632,6 @@ func TestDisallowedOptionsInConfig(t *testing.T) {
// Run with disallowed option set only in command-line // Run with disallowed option set only in command-line
testshared.NewRunnerBuilder(t). testshared.NewRunnerBuilder(t).
WithNoConfig(). WithNoConfig().
WithArgs("--skip-dirs", skipDirsCommand).
WithArgs(args...). WithArgs(args...).
WithTargetPath(testdataDir, minimalPkg). WithTargetPath(testdataDir, minimalPkg).
Runner(). Runner().
@ -644,7 +642,6 @@ func TestDisallowedOptionsInConfig(t *testing.T) {
testshared.NewRunnerBuilder(t). testshared.NewRunnerBuilder(t).
WithConfig(c.cfg). WithConfig(c.cfg).
WithArgs("--skip-dirs", skipDirsCommand).
WithArgs(args...). WithArgs(args...).
WithTargetPath(testdataDir, minimalPkg). WithTargetPath(testdataDir, minimalPkg).
Runner(). Runner().

View File

@ -0,0 +1 @@
io/ioutil.ReadFile

View File

@ -1,4 +1,4 @@
linters-settings: linters-settings:
errcheck: errcheck:
check-blank: true check-blank: true
exclude: testdata/errcheck/exclude.txt exclude: errcheck_exclude.txt

View File

@ -1 +0,0 @@
io/ioutil.ReadFile

View File

@ -1,5 +1,5 @@
//golangcitest:args -Eerrcheck //golangcitest:args -Eerrcheck
//golangcitest:config_path testdata/errcheck/exclude_functions.yml //golangcitest:config_path testdata/configs/exclude_functions.yml
package testdata package testdata
import ( import (

View File

@ -1,5 +1,5 @@
//golangcitest:args -Eerrcheck //golangcitest:args -Eerrcheck
//golangcitest:config_path testdata/errcheck/ignore_config.yml //golangcitest:config_path testdata/configs/ignore_config.yml
package testdata package testdata
import ( import (

View File

@ -1,3 +1,5 @@
//golangcitest:args -Egovet
//golangcitest:expected_exitcode 0
package main package main
import ( import (

View File

@ -301,10 +301,13 @@ func (r *RunnerResult) ExpectOutputRegexp(s string) *RunnerResult {
return r return r
} }
func (r *RunnerResult) ExpectOutputContains(s string) *RunnerResult { func (r *RunnerResult) ExpectOutputContains(s ...string) *RunnerResult {
r.tb.Helper() r.tb.Helper()
assert.Contains(r.tb, r.output, normalizeFilePath(s), "exit code is %d", r.exitCode) for _, expected := range s {
assert.Contains(r.tb, r.output, normalizeFilePath(expected), "exit code is %d", r.exitCode)
}
return r return r
} }