package lintersdb import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/tools/go/packages" "github.com/golangci/golangci-lint/pkg/config" "github.com/golangci/golangci-lint/pkg/goanalysis" "github.com/golangci/golangci-lint/pkg/lint/linter" "github.com/golangci/golangci-lint/pkg/logutils" ) func TestManager_GetEnabledLintersMap(t *testing.T) { cfg := config.NewDefault() cfg.Linters.DisableAll = true cfg.Linters.Enable = []string{"gofmt"} m, err := NewManager(logutils.NewStderrLog("skip"), cfg, NewLinterBuilder()) require.NoError(t, err) lintersMap, err := m.GetEnabledLintersMap() require.NoError(t, err) gofmtConfigs := m.GetLinterConfigs("gofmt") typecheckConfigs := m.GetLinterConfigs("typecheck") expected := map[string]*linter.Config{ "gofmt": gofmtConfigs[0], "typecheck": typecheckConfigs[0], } assert.Equal(t, expected, lintersMap) } func TestManager_GetOptimizedLinters(t *testing.T) { cfg := config.NewDefault() cfg.Linters.DisableAll = true cfg.Linters.Enable = []string{"gofmt"} m, err := NewManager(logutils.NewStderrLog("skip"), cfg, NewLinterBuilder()) require.NoError(t, err) optimizedLinters, err := m.GetOptimizedLinters() require.NoError(t, err) var gaLinters []*goanalysis.Linter for _, l := range m.GetLinterConfigs("gofmt") { gaLinters = append(gaLinters, l.Linter.(*goanalysis.Linter)) } for _, l := range m.GetLinterConfigs("typecheck") { gaLinters = append(gaLinters, l.Linter.(*goanalysis.Linter)) } mlConfig := &linter.Config{ Linter: goanalysis.NewMetaLinter(gaLinters), InPresets: []string{"format"}, } expected := []*linter.Config{mlConfig.WithLoadFiles()} assert.Equal(t, expected, optimizedLinters) } func TestManager_build(t *testing.T) { type cs struct { cfg config.Linters name string // test case name def []string // enabled by default linters exp []string // alphabetically ordered enabled linter names } allMegacheckLinterNames := []string{"gosimple", "staticcheck", "unused"} cases := []cs{ { cfg: config.Linters{ Disable: []string{"megacheck"}, }, name: "disable all linters from megacheck", def: allMegacheckLinterNames, exp: []string{"typecheck"}, // all disabled }, { cfg: config.Linters{ Disable: []string{"staticcheck"}, }, name: "disable only staticcheck", def: allMegacheckLinterNames, exp: []string{"gosimple", "typecheck", "unused"}, }, { name: "don't merge into megacheck", def: allMegacheckLinterNames, exp: []string{"gosimple", "staticcheck", "typecheck", "unused"}, }, { name: "expand megacheck", cfg: config.Linters{ Enable: []string{"megacheck"}, }, def: nil, exp: []string{"gosimple", "staticcheck", "typecheck", "unused"}, }, { name: "don't disable anything", def: []string{"gofmt", "govet", "typecheck"}, exp: []string{"gofmt", "govet", "typecheck"}, }, { name: "enable gosec by gas alias", cfg: config.Linters{ Enable: []string{"gas"}, }, exp: []string{"gosec", "typecheck"}, }, { name: "enable gosec by primary name", cfg: config.Linters{ Enable: []string{"gosec"}, }, exp: []string{"gosec", "typecheck"}, }, { name: "enable gosec by both names", cfg: config.Linters{ Enable: []string{"gosec", "gas"}, }, exp: []string{"gosec", "typecheck"}, }, { name: "disable gosec by gas alias", cfg: config.Linters{ Disable: []string{"gas"}, }, def: []string{"gosec"}, exp: []string{"typecheck"}, }, { name: "disable gosec by primary name", cfg: config.Linters{ Disable: []string{"gosec"}, }, def: []string{"gosec"}, exp: []string{"typecheck"}, }, } for _, c := range cases { c := c t.Run(c.name, func(t *testing.T) { m, err := NewManager(logutils.NewStderrLog("skip"), &config.Config{Linters: c.cfg}, NewLinterBuilder()) require.NoError(t, err) var defaultLinters []*linter.Config for _, ln := range c.def { lcs := m.GetLinterConfigs(ln) assert.NotNil(t, lcs, ln) defaultLinters = append(defaultLinters, lcs...) } els := m.build(defaultLinters) var enabledLinters []string for ln, lc := range els { assert.Equal(t, ln, lc.Name()) enabledLinters = append(enabledLinters, ln) } assert.ElementsMatch(t, c.exp, enabledLinters) }) } } func TestManager_combineGoAnalysisLinters(t *testing.T) { m, err := NewManager(nil, nil) require.NoError(t, err) fooTyped := goanalysis.NewLinter("foo", "example foo", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo) barTyped := goanalysis.NewLinter("bar", "example bar", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo) fooSyntax := goanalysis.NewLinter("foo", "example foo", nil, nil).WithLoadMode(goanalysis.LoadModeSyntax) barSyntax := goanalysis.NewLinter("bar", "example bar", nil, nil).WithLoadMode(goanalysis.LoadModeSyntax) testCases := []struct { desc string linters map[string]*linter.Config expected map[string]*linter.Config }{ { desc: "no combined, one linter", linters: map[string]*linter.Config{ "foo": { Linter: fooTyped, InPresets: []string{"A"}, }, }, expected: map[string]*linter.Config{ "foo": { Linter: fooTyped, InPresets: []string{"A"}, }, }, }, { desc: "combined, several linters (typed)", linters: map[string]*linter.Config{ "foo": { Linter: fooTyped, InPresets: []string{"A"}, }, "bar": { Linter: barTyped, InPresets: []string{"B"}, }, }, expected: func() map[string]*linter.Config { mlConfig := &linter.Config{ Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{barTyped, fooTyped}), InPresets: []string{"A", "B"}, } return map[string]*linter.Config{ "goanalysis_metalinter": mlConfig, } }(), }, { desc: "combined, several linters (different LoadMode)", linters: map[string]*linter.Config{ "foo": { Linter: fooTyped, InPresets: []string{"A"}, LoadMode: packages.NeedName, }, "bar": { Linter: barTyped, InPresets: []string{"B"}, LoadMode: packages.NeedTypesSizes, }, }, expected: func() map[string]*linter.Config { mlConfig := &linter.Config{ Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{barTyped, fooTyped}), InPresets: []string{"A", "B"}, LoadMode: packages.NeedName | packages.NeedTypesSizes, } return map[string]*linter.Config{ "goanalysis_metalinter": mlConfig, } }(), }, { desc: "combined, several linters (same LoadMode)", linters: map[string]*linter.Config{ "foo": { Linter: fooTyped, InPresets: []string{"A"}, LoadMode: packages.NeedName, }, "bar": { Linter: barTyped, InPresets: []string{"B"}, LoadMode: packages.NeedName, }, }, expected: func() map[string]*linter.Config { mlConfig := &linter.Config{ Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{barTyped, fooTyped}), InPresets: []string{"A", "B"}, LoadMode: packages.NeedName, } return map[string]*linter.Config{ "goanalysis_metalinter": mlConfig, } }(), }, { desc: "combined, several linters (syntax)", linters: map[string]*linter.Config{ "foo": { Linter: fooSyntax, InPresets: []string{"A"}, }, "bar": { Linter: barSyntax, InPresets: []string{"B"}, }, }, expected: func() map[string]*linter.Config { mlConfig := &linter.Config{ Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{barSyntax, fooSyntax}), InPresets: []string{"A", "B"}, } return map[string]*linter.Config{ "goanalysis_metalinter": mlConfig, } }(), }, } for _, test := range testCases { test := test t.Run(test.desc, func(t *testing.T) { t.Parallel() m.combineGoAnalysisLinters(test.linters) assert.Equal(t, test.expected, test.linters) }) } }