package test import ( "os" "os/exec" "path/filepath" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/golangci/golangci-lint/pkg/logutils" "github.com/golangci/golangci-lint/test/testshared" ) const testdataDir = "testdata" func TestSourcesFromTestdata(t *testing.T) { testSourcesFromDir(t, testdataDir) } func TestTypecheck(t *testing.T) { testshared.SkipOnWindows(t) testSourcesFromDir(t, filepath.Join(testdataDir, "notcompiles")) } func TestSourcesFromTestdataSubDir(t *testing.T) { subDirs := []string{ "loggercheck", "ginkgolinter", "zerologlint", "protogetter", } for _, dir := range subDirs { t.Run(dir, func(t *testing.T) { testSourcesFromDir(t, filepath.Join(testdataDir, dir)) }) } } func testSourcesFromDir(t *testing.T, dir string) { t.Helper() t.Log(filepath.Join(dir, "*.go")) sources := findSources(t, dir, "*.go") binPath := testshared.InstallGolangciLint(t) cwd, err := os.Getwd() require.NoError(t, err) t.Cleanup(func() { _ = os.Chdir(cwd) }) err = os.Chdir(dir) require.NoError(t, err) log := logutils.NewStderrLog(logutils.DebugKeyTest) log.SetLevel(logutils.LogLevelInfo) for _, source := range sources { source := source t.Run(filepath.Base(source), func(subTest *testing.T) { subTest.Parallel() rel, err := filepath.Rel(dir, source) require.NoError(t, err) testOneSource(subTest, log, binPath, rel) }) } } func testOneSource(t *testing.T, log *logutils.StderrLog, binPath, sourcePath string) { t.Helper() rc := testshared.ParseTestDirectives(t, sourcePath) if rc == nil { t.Skipf("Skipped: %s", sourcePath) } args := []string{ "--allow-parallel-runners", "--disable-all", "--out-format=json", "--max-same-issues=100", } for _, addArg := range []string{"", "-Etypecheck"} { caseArgs := append([]string{}, args...) if addArg != "" { caseArgs = append(caseArgs, addArg) } cmd := testshared.NewRunnerBuilder(t). WithBinPath(binPath). WithNoParallelRunners(). WithArgs(caseArgs...). WithRunContext(rc). WithTargetPath(sourcePath). Runner(). Command() startedAt := time.Now() output, err := cmd.CombinedOutput() log.Infof("ran [%s] in %s", strings.Join(cmd.Args, " "), time.Since(startedAt)) // The returned error will be nil if the test file does not have any issues // and thus the linter exits with exit code 0. // So perform the additional assertions only if the error is non-nil. if err != nil { var exitErr *exec.ExitError require.ErrorAs(t, err, &exitErr) } assert.Equal(t, rc.ExitCode, cmd.ProcessState.ExitCode(), "Unexpected exit code: %s", string(output)) testshared.Analyze(t, sourcePath, output) } } func findSources(t *testing.T, pathPatterns ...string) []string { t.Helper() sources, err := filepath.Glob(filepath.Join(pathPatterns...)) require.NoError(t, err) require.NotEmpty(t, sources) return sources }