golangci-lint/test/run_test.go
Isaev Denis cb58d1f82e
speed up CI and golangci-lint (#1070)
Run CI on mac os only with go1.13 and on windows only on go1.14.
Speed up tests. Introduce --allow-parallel-runners.
Block on parallel run lock 5s instead of 60s.
Don't invalidate analysis cache for minor config changes.
2020-05-09 15:15:34 +03:00

295 lines
10 KiB
Go

package test
import (
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
_ "github.com/valyala/quicktemplate"
"github.com/golangci/golangci-lint/pkg/exitcodes"
"github.com/golangci/golangci-lint/test/testshared"
)
func getCommonRunArgs() []string {
return []string{"--skip-dirs", "testdata_etc/,pkg/golinters/goanalysis/(checker|passes)"}
}
func withCommonRunArgs(args ...string) []string {
return append(getCommonRunArgs(), args...)
}
func TestAutogeneratedNoIssues(t *testing.T) {
testshared.NewLintRunner(t).Run(getTestDataDir("autogenerated")).ExpectNoIssues()
}
func TestEmptyDirRun(t *testing.T) {
testshared.NewLintRunner(t, "GO111MODULE=off").Run(getTestDataDir("nogofiles")).
ExpectExitCode(exitcodes.NoGoFiles).
ExpectOutputContains(": no go files to analyze")
}
func TestNotExistingDirRun(t *testing.T) {
testshared.NewLintRunner(t, "GO111MODULE=off").Run(getTestDataDir("no_such_dir")).
ExpectExitCode(exitcodes.Failure).
ExpectOutputContains("cannot find package").
ExpectOutputContains("/testdata/no_such_dir")
}
func TestSymlinkLoop(t *testing.T) {
testshared.NewLintRunner(t).Run(getTestDataDir("symlink_loop", "...")).ExpectNoIssues()
}
func TestDeadline(t *testing.T) {
testshared.NewLintRunner(t).Run("--deadline=1ms", getProjectRoot()).
ExpectExitCode(exitcodes.Timeout).
ExpectOutputContains(`Timeout exceeded: try increasing it by passing --timeout option`)
}
func TestTimeout(t *testing.T) {
testshared.NewLintRunner(t).Run("--timeout=1ms", getProjectRoot()).
ExpectExitCode(exitcodes.Timeout).
ExpectOutputContains(`Timeout exceeded: try increasing it by passing --timeout option`)
}
func TestTimeoutInConfig(t *testing.T) {
type tc struct {
cfg string
}
cases := []tc{
{
cfg: `
run:
deadline: 1ms
`,
},
{
cfg: `
run:
timeout: 1ms
`,
},
{
// timeout should override deadline
cfg: `
run:
deadline: 100s
timeout: 1ms
`,
},
}
r := testshared.NewLintRunner(t)
for _, c := range cases {
// Run with disallowed option set only in config
r.RunWithYamlConfig(c.cfg, withCommonRunArgs(minimalPkg)...).ExpectExitCode(exitcodes.Timeout).
ExpectOutputContains(`Timeout exceeded: try increasing it by passing --timeout option`)
}
}
func TestTestsAreLintedByDefault(t *testing.T) {
testshared.NewLintRunner(t).Run(getTestDataDir("withtests")).
ExpectHasIssue("`if` block ends with a `return`")
}
func TestCgoOk(t *testing.T) {
testshared.NewLintRunner(t).Run("--no-config", "--enable-all", getTestDataDir("cgo")).ExpectNoIssues()
}
func TestCgoWithIssues(t *testing.T) {
r := testshared.NewLintRunner(t)
r.Run("--no-config", "--disable-all", "-Egovet", getTestDataDir("cgo_with_issues")).
ExpectHasIssue("Printf format %t has arg cs of wrong type")
r.Run("--no-config", "--disable-all", "-Estaticcheck", getTestDataDir("cgo_with_issues")).
ExpectHasIssue("SA5009: Printf format %t has arg #1 of wrong type")
}
func TestUnsafeOk(t *testing.T) {
testshared.NewLintRunner(t).Run("--no-config", "--enable-all", getTestDataDir("unsafe")).ExpectNoIssues()
}
func TestGovetCustomFormatter(t *testing.T) {
testshared.NewLintRunner(t).Run(getTestDataDir("govet_custom_formatter")).ExpectNoIssues()
}
func TestLineDirectiveProcessedFilesLiteLoading(t *testing.T) {
r := testshared.NewLintRunner(t).Run("--print-issued-lines=false", "--no-config",
"--exclude-use-default=false", "-Egolint", getTestDataDir("quicktemplate"))
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")
r.ExpectExitCode(exitcodes.IssuesFound).ExpectOutputEq(output + "\n")
}
func TestLineDirectiveProcessedFilesFullLoading(t *testing.T) {
r := testshared.NewLintRunner(t).Run("--print-issued-lines=false", "--no-config",
"--exclude-use-default=false", "-Egolint,govet", getTestDataDir("quicktemplate"))
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")
r.ExpectExitCode(exitcodes.IssuesFound).ExpectOutputEq(output + "\n")
}
func TestLintFilesWithLineDirective(t *testing.T) {
r := testshared.NewLintRunner(t)
r.Run("-Edupl", "--disable-all", "--config=testdata/linedirective/dupl.yml", getTestDataDir("linedirective")).
ExpectHasIssue("21-23 lines are duplicate of `testdata/linedirective/hello.go:25-27` (dupl)")
r.Run("-Egofmt", "--disable-all", "--no-config", getTestDataDir("linedirective")).
ExpectHasIssue("File is not `gofmt`-ed with `-s` (gofmt)")
r.Run("-Egoimports", "--disable-all", "--no-config", getTestDataDir("linedirective")).
ExpectHasIssue("File is not `goimports`-ed (goimports)")
r.
Run("-Egomodguard", "--disable-all", "--config=testdata/linedirective/gomodguard.yml", getTestDataDir("linedirective")).
ExpectHasIssue("import of package `github.com/ryancurrah/gomodguard` is blocked because the module is not " +
"in the allowed modules list. (gomodguard)")
r.Run("-Eineffassign", "--disable-all", "--no-config", getTestDataDir("linedirective")).
ExpectHasIssue("ineffectual assignment to `x` (ineffassign)")
r.Run("-Elll", "--disable-all", "--config=testdata/linedirective/lll.yml", getTestDataDir("linedirective")).
ExpectHasIssue("line is 57 characters (lll)")
r.Run("-Emisspell", "--disable-all", "--no-config", getTestDataDir("linedirective")).
ExpectHasIssue("is a misspelling of `language` (misspell)")
r.Run("-Ewsl", "--disable-all", "--no-config", getTestDataDir("linedirective")).
ExpectHasIssue("block should not start with a whitespace (wsl)")
}
func TestSkippedDirsNoMatchArg(t *testing.T) {
dir := getTestDataDir("skipdirs", "skip_me", "nested")
res := testshared.NewLintRunner(t).Run("--print-issued-lines=false", "--no-config", "--skip-dirs", dir, "-Egolint", dir)
res.ExpectExitCode(exitcodes.IssuesFound).
ExpectOutputEq("testdata/skipdirs/skip_me/nested/with_issue.go:8:9: `if` block ends with " +
"a `return` statement, so drop this `else` and outdent its block (golint)\n")
}
func TestSkippedDirsTestdata(t *testing.T) {
r := testshared.NewLintRunner(t).Run("--print-issued-lines=false", "--no-config", "-Egolint", getTestDataDir("skipdirs", "..."))
r.ExpectNoIssues() // all was skipped because in testdata
}
func TestDeadcodeNoFalsePositivesInMainPkg(t *testing.T) {
testshared.NewLintRunner(t).Run("--no-config", "--disable-all", "-Edeadcode", getTestDataDir("deadcode_main_pkg")).ExpectNoIssues()
}
func TestIdentifierUsedOnlyInTests(t *testing.T) {
testshared.NewLintRunner(t).Run("--no-config", "--disable-all", "-Eunused", getTestDataDir("used_only_in_tests")).ExpectNoIssues()
}
func TestUnusedCheckExported(t *testing.T) {
t.Skip("Issue955")
testshared.NewLintRunner(t).Run("-c", "testdata_etc/unused_exported/golangci.yml", "testdata_etc/unused_exported/...").ExpectNoIssues()
}
func TestConfigFileIsDetected(t *testing.T) {
checkGotConfig := func(r *testshared.RunResult) {
r.ExpectExitCode(exitcodes.Success).
ExpectOutputEq("test\n") // test config contains InternalTest: true, it triggers such output
}
r := testshared.NewLintRunner(t)
checkGotConfig(r.Run(getTestDataDir("withconfig", "pkg")))
checkGotConfig(r.Run(getTestDataDir("withconfig", "...")))
}
func TestEnableAllFastAndEnableCanCoexist(t *testing.T) {
r := testshared.NewLintRunner(t)
r.Run(withCommonRunArgs("--no-config", "--fast", "--enable-all", "--enable=typecheck", minimalPkg)...).
ExpectExitCode(exitcodes.Success, exitcodes.IssuesFound)
r.Run(withCommonRunArgs("--no-config", "--enable-all", "--enable=typecheck", minimalPkg)...).
ExpectExitCode(exitcodes.Failure)
}
func TestEnabledPresetsAreNotDuplicated(t *testing.T) {
testshared.NewLintRunner(t).Run("--no-config", "-v", "-p", "style,bugs", minimalPkg).
ExpectOutputContains("Active presets: [bugs style]")
}
func TestAbsPathDirAnalysis(t *testing.T) {
dir := filepath.Join("testdata_etc", "abspath") // abs paths don't work with testdata dir
absDir, err := filepath.Abs(dir)
assert.NoError(t, err)
r := testshared.NewLintRunner(t).Run("--print-issued-lines=false", "--no-config", "-Egolint", absDir)
r.ExpectHasIssue("`if` block ends with a `return` statement")
}
func TestAbsPathFileAnalysis(t *testing.T) {
dir := filepath.Join("testdata_etc", "abspath", "with_issue.go") // abs paths don't work with testdata dir
absDir, err := filepath.Abs(dir)
assert.NoError(t, err)
r := testshared.NewLintRunner(t).Run("--print-issued-lines=false", "--no-config", "-Egolint", absDir)
r.ExpectHasIssue("`if` block ends with a `return` statement")
}
func TestDisallowedOptionsInConfig(t *testing.T) {
type tc struct {
cfg string
option string
}
cases := []tc{
{
cfg: `
ruN:
Args:
- 1
`,
},
{
cfg: `
run:
CPUProfilePath: path
`,
option: "--cpu-profile-path=path",
},
{
cfg: `
run:
MemProfilePath: path
`,
option: "--mem-profile-path=path",
},
{
cfg: `
run:
TracePath: path
`,
option: "--trace-path=path",
},
{
cfg: `
run:
Verbose: true
`,
option: "-v",
},
}
r := testshared.NewLintRunner(t)
for _, c := range cases {
// Run with disallowed option set only in config
r.RunWithYamlConfig(c.cfg, withCommonRunArgs(minimalPkg)...).ExpectExitCode(exitcodes.Failure)
if c.option == "" {
continue
}
args := []string{c.option, "--fast", minimalPkg}
// Run with disallowed option set only in command-line
r.Run(withCommonRunArgs(args...)...).ExpectExitCode(exitcodes.Success)
// Run with disallowed option set both in command-line and in config
r.RunWithYamlConfig(c.cfg, withCommonRunArgs(args...)...).ExpectExitCode(exitcodes.Failure)
}
}