diff --git a/.golangci.next.reference.yml b/.golangci.next.reference.yml index c87aec032978..f868c842eaf9 100644 --- a/.golangci.next.reference.yml +++ b/.golangci.next.reference.yml @@ -2192,13 +2192,16 @@ linters-settings: - error-nil - expected-actual - float-compare + - formatter - go-require - len - negative-positive - nil-compare - require-error + - suite-broken-parallel - suite-dont-use-pkg - suite-extra-assert-call + - suite-subtest-run - suite-thelper - useless-assert @@ -2208,7 +2211,8 @@ linters-settings: # Enable checkers by name # (in addition to default # blank-import, bool-compare, compares, empty, error-is-as, error-nil, expected-actual, go-require, float-compare, - # len, negative-positive, nil-compare, require-error, suite-dont-use-pkg, suite-extra-assert-call, useless-assert + # formatter, len, negative-positive, nil-compare, require-error, suite-broken-parallel, suite-dont-use-pkg, + # suite-extra-assert-call, suite-subtest-run, useless-assert # ). enable: - blank-import @@ -2219,13 +2223,16 @@ linters-settings: - error-nil - expected-actual - float-compare + - formatter - go-require - len - negative-positive - nil-compare - require-error + - suite-broken-parallel - suite-dont-use-pkg - suite-extra-assert-call + - suite-subtest-run - suite-thelper - useless-assert @@ -2237,6 +2244,13 @@ linters-settings: # Regexp for expected variable name. # Default: (^(exp(ected)?|want(ed)?)([A-Z]\w*)?$)|(^(\w*[a-z])?(Exp(ected)?|Want(ed)?)$) pattern: ^expected + formatter: + # To enable go vet's printf checks. + # Default: true + check-format-string: false + # To require f-assertions if format string is used. + # Default: false + require-f-funcs: true go-require: # To ignore HTTP handlers (like http.HandlerFunc). # Default: false diff --git a/go.mod b/go.mod index b57c38660459..6d0feba900d5 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/Abirdcfly/dupword v0.0.14 github.com/Antonboom/errname v0.1.13 github.com/Antonboom/nilnil v0.1.9 - github.com/Antonboom/testifylint v1.3.1 + github.com/Antonboom/testifylint v1.4.1 github.com/BurntSushi/toml v1.4.0 github.com/Crocmagnon/fatcontext v0.3.0 github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 diff --git a/go.sum b/go.sum index 4100c3b8140a..a5d9fa76c490 100644 --- a/go.sum +++ b/go.sum @@ -43,8 +43,8 @@ github.com/Antonboom/errname v0.1.13 h1:JHICqsewj/fNckzrfVSe+T33svwQxmjC+1ntDsHO github.com/Antonboom/errname v0.1.13/go.mod h1:uWyefRYRN54lBg6HseYCFhs6Qjcy41Y3Jl/dVhA87Ns= github.com/Antonboom/nilnil v0.1.9 h1:eKFMejSxPSA9eLSensFmjW2XTgTwJMjZ8hUHtV4s/SQ= github.com/Antonboom/nilnil v0.1.9/go.mod h1:iGe2rYwCq5/Me1khrysB4nwI7swQvjclR8/YRPl5ihQ= -github.com/Antonboom/testifylint v1.3.1 h1:Uam4q1Q+2b6H7gvk9RQFw6jyVDdpzIirFOOrbs14eG4= -github.com/Antonboom/testifylint v1.3.1/go.mod h1:NV0hTlteCkViPW9mSR4wEMfwp+Hs1T3dY60bkvSfhpM= +github.com/Antonboom/testifylint v1.4.1 h1:LeBVoSeqCgJoHqwu46yzm7Zgcm6T7QhDYfT9VtFIRpg= +github.com/Antonboom/testifylint v1.4.1/go.mod h1:+8Q9+AOLsz5ZiQiiYujJKs9mNz398+M6UgslP4qgJLA= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= diff --git a/jsonschema/golangci.next.jsonschema.json b/jsonschema/golangci.next.jsonschema.json index 66b2cc742a6d..0999c278efe7 100644 --- a/jsonschema/golangci.next.jsonschema.json +++ b/jsonschema/golangci.next.jsonschema.json @@ -2886,13 +2886,16 @@ "error-nil", "expected-actual", "float-compare", + "formatter", "go-require", "len", "negative-positive", "nil-compare", "require-error", + "suite-broken-parallel", "suite-dont-use-pkg", "suite-extra-assert-call", + "suite-subtest-run", "suite-thelper", "useless-assert" ] @@ -2906,13 +2909,16 @@ "error-nil", "expected-actual", "float-compare", + "float-compare", "go-require", "len", "negative-positive", "nil-compare", "require-error", + "suite-broken-parallel", "suite-dont-use-pkg", "suite-extra-assert-call", + "suite-subtest-run", "useless-assert" ] }, @@ -2929,13 +2935,16 @@ "error-nil", "expected-actual", "float-compare", + "formatter", "go-require", "len", "negative-positive", "nil-compare", "require-error", + "suite-broken-parallel", "suite-dont-use-pkg", "suite-extra-assert-call", + "suite-subtest-run", "suite-thelper", "useless-assert" ], @@ -2966,6 +2975,22 @@ } } }, + "formatter": { + "type": "object", + "additionalProperties": false, + "properties": { + "check-format-string": { + "description": "To enable go vet's printf checks.", + "type": "boolean", + "default": true + }, + "require-f-funcs": { + "description": "To require f-assertions if format string is used.", + "type": "boolean", + "default": false + } + } + }, "go-require": { "type": "object", "additionalProperties": false, diff --git a/pkg/config/linters_settings.go b/pkg/config/linters_settings.go index b2f4567d494d..f159db2a96d8 100644 --- a/pkg/config/linters_settings.go +++ b/pkg/config/linters_settings.go @@ -879,6 +879,11 @@ type TestifylintSettings struct { ExpVarPattern string `mapstructure:"pattern"` } `mapstructure:"expected-actual"` + Formatter struct { + CheckFormatString *bool `mapstructure:"check-format-string"` + RequireFFuncs bool `mapstructure:"require-f-funcs"` + } `mapstructure:"formatter"` + GoRequire struct { IgnoreHTTPHandlers bool `mapstructure:"ignore-http-handlers"` } `mapstructure:"go-require"` diff --git a/pkg/golinters/testifylint/testdata/testifylint.go b/pkg/golinters/testifylint/testdata/testifylint.go index 3de4bad1985b..a79161f9ca7a 100644 --- a/pkg/golinters/testifylint/testdata/testifylint.go +++ b/pkg/golinters/testifylint/testdata/testifylint.go @@ -2,6 +2,7 @@ package testdata import ( + "fmt" "io" "testing" @@ -21,15 +22,15 @@ func TestTestifylint(t *testing.T) { err error ) - assert.Equal(t, predicate, true) // want "bool-compare: use assert\\.True" - assert.Equal(t, Bool(predicate), false) // want "bool-compare: use assert\\.False" - assert.True(t, resultInt == 1) // want "compares: use assert\\.Equal" - assert.Equal(t, len(arr), 0) // want "empty: use assert\\.Empty" - assert.Error(t, err, io.EOF) // want "error-is-as: invalid usage of assert\\.Error, use assert\\.ErrorIs instead" - assert.Nil(t, err) // want "error-nil: use assert\\.NoError" - assert.Equal(t, resultInt, 42) // want "expected-actual: need to reverse actual and expected values" - assert.Equal(t, resultFloat, 42.42) // want "float-compare: use assert\\.InEpsilon \\(or InDelta\\)" - assert.Equal(t, len(arr), 10) // want "len: use assert\\.Len" + assert.Equal(t, predicate, true) // want "bool-compare: use assert\\.True" + assert.Equal(t, Bool(predicate), false) // want "bool-compare: use assert\\.False" + assert.True(t, resultInt == 1) // want "compares: use assert\\.Equal" + assert.Equal(t, len(arr), 0) // want "empty: use assert\\.Empty" + assert.Error(t, err, io.EOF) // want "error-is-as: invalid usage of assert\\.Error, use assert\\.ErrorIs instead" + assert.Nil(t, err) // want "error-nil: use assert\\.NoError" + assert.Equal(t, resultInt, 42) // want "expected-actual: need to reverse actual and expected values" + assert.Equal(t, resultFloat, 42.42) // want "float-compare: use assert\\.InEpsilon \\(or InDelta\\)" + assert.Equal(t, len(arr), 10) // want "len: use assert\\.Len" assert.True(t, predicate) assert.Equal(t, resultInt, 1) // want "expected-actual: need to reverse actual and expected values" @@ -48,6 +49,9 @@ func TestTestifylint(t *testing.T) { assert.Equal(t, predicate, true, "message %d", 42) // want "bool-compare: use assert\\.True" assert.Equalf(t, predicate, true, "message") // want "bool-compare: use assert\\.Truef" assert.Equalf(t, predicate, true, "message %d", 42) // want "bool-compare: use assert\\.Truef" + + assert.Equal(t, 1, 2, fmt.Sprintf("msg")) // want "formatter: remove unnecessary fmt\\.Sprintf" + assert.Equalf(t, 1, 2, "msg with arg", "arg") // want "formatter: assert\\.Equalf call has arguments but no formatting directives" }) assert.Equal(t, arr, nil) // want "nil-compare: use assert\\.Nil" @@ -72,3 +76,22 @@ func (s *SuiteExample) TestAll() { var b bool s.Assert().True(b) // want "suite-extra-assert-call: need to simplify the assertion to s\\.True" } + +func (s *SuiteExample) TestOne() { + s.T().Parallel() // want "suite-broken-parallel: testify v1 does not support suite's parallel tests and subtests" + + s.T().Run("subtest", func(t *testing.T) { // want "suite-subtest-run: use s\\.Run to run subtest" + t.Parallel() // want "suite-broken-parallel: testify v1 does not support suite's parallel tests and subtests" + + assert.Equal(s.T(), 1, 2) // want "suite-dont-use-pkg: use s\\.Equal" + s.Equal(1, 2) + }) + + s.Run("subtest", func() { + s.T().Parallel() // want "suite-broken-parallel: testify v1 does not support suite's parallel tests and subtests" + s.Equal(1, 2) + }) + + var b bool + s.Assert().True(b) // want "suite-extra-assert-call: need to simplify the assertion to s\\.True" +} diff --git a/pkg/golinters/testifylint/testdata/testifylint_formatter_only.go b/pkg/golinters/testifylint/testdata/testifylint_formatter_only.go new file mode 100644 index 000000000000..0128e55c5089 --- /dev/null +++ b/pkg/golinters/testifylint/testdata/testifylint_formatter_only.go @@ -0,0 +1,19 @@ +//golangcitest:args -Etestifylint +//golangcitest:config_path testdata/testifylint_formatter_only.yml +package testdata + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestTestifylint(t *testing.T) { + var err error + var args []any + assert.Error(t, err, "Parse(%v) should fail.", args) // want "formatter: use assert\\.Errorf$" + + assert.Equal(t, 1, 2, fmt.Sprintf("msg")) // want "formatter: remove unnecessary fmt\\.Sprintf and use assert\\.Equalf" + assert.DirExistsf(t, "", "msg with arg", 42) +} diff --git a/pkg/golinters/testifylint/testdata/testifylint_formatter_only.yml b/pkg/golinters/testifylint/testdata/testifylint_formatter_only.yml new file mode 100644 index 000000000000..185fc39daedb --- /dev/null +++ b/pkg/golinters/testifylint/testdata/testifylint_formatter_only.yml @@ -0,0 +1,8 @@ +linters-settings: + testifylint: + disable-all: true + enable: + - formatter + formatter: + check-format-string: false + require-f-funcs: true diff --git a/pkg/golinters/testifylint/testifylint.go b/pkg/golinters/testifylint/testifylint.go index a5f95a1e83a4..b3f2f0bd4697 100644 --- a/pkg/golinters/testifylint/testifylint.go +++ b/pkg/golinters/testifylint/testifylint.go @@ -18,6 +18,7 @@ func New(settings *config.TestifylintSettings) *goanalysis.Linter { "disable-all": settings.DisableAll, "bool-compare.ignore-custom-types": settings.BoolCompare.IgnoreCustomTypes, + "formatter.require-f-funcs": settings.Formatter.RequireFFuncs, "go-require.ignore-http-handlers": settings.GoRequire.IgnoreHTTPHandlers, } if len(settings.EnabledCheckers) > 0 { @@ -27,6 +28,9 @@ func New(settings *config.TestifylintSettings) *goanalysis.Linter { cfg[a.Name]["disable"] = settings.DisabledCheckers } + if b := settings.Formatter.CheckFormatString; b != nil { + cfg[a.Name]["formatter.check-format-string"] = *b + } if p := settings.ExpectedActual.ExpVarPattern; p != "" { cfg[a.Name]["expected-actual.pattern"] = p }