diff --git a/README.md b/README.md index 11587b4c..b1c6380b 100644 --- a/README.md +++ b/README.md @@ -340,12 +340,16 @@ logic, but without autofix. ```go ❌ assert.Nil(t, err) -assert.NotNil(t, err) +assert.Empty(t, err) +assert.Zero(t, err) assert.Equal(t, nil, err) assert.EqualValues(t, nil, err) assert.Exactly(t, nil, err) assert.ErrorIs(t, err, nil) +assert.NotNil(t, err) +assert.NotEmpty(t, err) +assert.NotZero(t, err) assert.NotEqual(t, nil, err) assert.NotEqualValues(t, nil, err) assert.NotErrorIs(t, err, nil) diff --git a/analyzer/testdata/src/checkers-default/error-nil/error_nil_test.go b/analyzer/testdata/src/checkers-default/error-nil/error_nil_test.go index 407b90a3..a7396e1b 100644 --- a/analyzer/testdata/src/checkers-default/error-nil/error_nil_test.go +++ b/analyzer/testdata/src/checkers-default/error-nil/error_nil_test.go @@ -12,13 +12,16 @@ import ( func TestErrorNilChecker(t *testing.T) { var err error + var errs []error // Invalid. { assert.Nil(t, err) // want "error-nil: use assert\\.NoError" assert.Nilf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.NoErrorf" - assert.NotNil(t, err) // want "error-nil: use assert\\.Error" - assert.NotNilf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.Errorf" + assert.Empty(t, err) // want "error-nil: use assert\\.NoError" + assert.Emptyf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.NoErrorf" + assert.Zero(t, err) // want "error-nil: use assert\\.NoError" + assert.Zerof(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.NoErrorf" assert.Equal(t, err, nil) // want "error-nil: use assert\\.NoError" assert.Equalf(t, err, nil, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.NoErrorf" assert.Equal(t, nil, err) // want "error-nil: use assert\\.NoError" @@ -31,6 +34,14 @@ func TestErrorNilChecker(t *testing.T) { assert.Exactlyf(t, err, nil, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.NoErrorf" assert.Exactly(t, nil, err) // want "error-nil: use assert\\.NoError" assert.Exactlyf(t, nil, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.NoErrorf" + assert.ErrorIs(t, err, nil) // want "error-nil: use assert\\.NoError" + assert.ErrorIsf(t, err, nil, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.NoErrorf" + assert.NotNil(t, err) // want "error-nil: use assert\\.Error" + assert.NotNilf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.Errorf" + assert.NotEmpty(t, err) // want "error-nil: use assert\\.Error" + assert.NotEmptyf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.Errorf" + assert.NotZero(t, err) // want "error-nil: use assert\\.Error" + assert.NotZerof(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.Errorf" assert.NotEqual(t, err, nil) // want "error-nil: use assert\\.Error" assert.NotEqualf(t, err, nil, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.Errorf" assert.NotEqual(t, nil, err) // want "error-nil: use assert\\.Error" @@ -39,8 +50,6 @@ func TestErrorNilChecker(t *testing.T) { assert.NotEqualValuesf(t, err, nil, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.Errorf" assert.NotEqualValues(t, nil, err) // want "error-nil: use assert\\.Error" assert.NotEqualValuesf(t, nil, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.Errorf" - assert.ErrorIs(t, err, nil) // want "error-nil: use assert\\.NoError" - assert.ErrorIsf(t, err, nil, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.NoErrorf" assert.NotErrorIs(t, err, nil) // want "error-nil: use assert\\.Error" assert.NotErrorIsf(t, err, nil, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.Errorf" } @@ -67,6 +76,26 @@ func TestErrorNilChecker(t *testing.T) { assert.NotEqualf(t, err, err, "msg with args %d %s", 42, "42") assert.NotEqual(t, nil, nil) assert.NotEqualf(t, nil, nil, "msg with args %d %s", 42, "42") + assert.Empty(t, err.Error()) + assert.Emptyf(t, err.Error(), "msg with args %d %s", 42, "42") + assert.NotEmpty(t, err.Error()) + assert.NotEmptyf(t, err.Error(), "msg with args %d %s", 42, "42") + assert.Zero(t, err.Error()) + assert.Zerof(t, err.Error(), "msg with args %d %s", 42, "42") + assert.NotZero(t, err.Error()) + assert.NotZerof(t, err.Error(), "msg with args %d %s", 42, "42") + assert.Nil(t, errs) + assert.Nilf(t, errs, "msg with args %d %s", 42, "42") + assert.NotNil(t, errs) + assert.NotNilf(t, errs, "msg with args %d %s", 42, "42") + assert.Empty(t, errs) + assert.Emptyf(t, errs, "msg with args %d %s", 42, "42") + assert.NotEmpty(t, errs) + assert.NotEmptyf(t, errs, "msg with args %d %s", 42, "42") + assert.Zero(t, errs) + assert.Zerof(t, errs, "msg with args %d %s", 42, "42") + assert.NotZero(t, errs) + assert.NotZerof(t, errs, "msg with args %d %s", 42, "42") } } diff --git a/analyzer/testdata/src/checkers-default/error-nil/error_nil_test.go.golden b/analyzer/testdata/src/checkers-default/error-nil/error_nil_test.go.golden index ba25565f..658ef19f 100644 --- a/analyzer/testdata/src/checkers-default/error-nil/error_nil_test.go.golden +++ b/analyzer/testdata/src/checkers-default/error-nil/error_nil_test.go.golden @@ -12,13 +12,18 @@ import ( func TestErrorNilChecker(t *testing.T) { var err error + var errs []error // Invalid. { assert.NoError(t, err) // want "error-nil: use assert\\.NoError" assert.NoErrorf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.NoErrorf" - assert.Error(t, err) // want "error-nil: use assert\\.Error" - assert.Errorf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.Errorf" + assert.NoError(t, err) // want "error-nil: use assert\\.NoError" + assert.NoErrorf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.NoErrorf" + assert.NoError(t, err) // want "error-nil: use assert\\.NoError" + assert.NoErrorf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.NoErrorf" + assert.NoError(t, err) // want "error-nil: use assert\\.NoError" + assert.NoErrorf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.NoErrorf" assert.NoError(t, err) // want "error-nil: use assert\\.NoError" assert.NoErrorf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.NoErrorf" assert.NoError(t, err) // want "error-nil: use assert\\.NoError" @@ -39,8 +44,12 @@ func TestErrorNilChecker(t *testing.T) { assert.Errorf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.Errorf" assert.Error(t, err) // want "error-nil: use assert\\.Error" assert.Errorf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.Errorf" - assert.NoError(t, err) // want "error-nil: use assert\\.NoError" - assert.NoErrorf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.NoErrorf" + assert.Error(t, err) // want "error-nil: use assert\\.Error" + assert.Errorf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.Errorf" + assert.Error(t, err) // want "error-nil: use assert\\.Error" + assert.Errorf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.Errorf" + assert.Error(t, err) // want "error-nil: use assert\\.Error" + assert.Errorf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.Errorf" assert.Error(t, err) // want "error-nil: use assert\\.Error" assert.Errorf(t, err, "msg with args %d %s", 42, "42") // want "error-nil: use assert\\.Errorf" } @@ -67,6 +76,26 @@ func TestErrorNilChecker(t *testing.T) { assert.NotEqualf(t, err, err, "msg with args %d %s", 42, "42") assert.NotEqual(t, nil, nil) assert.NotEqualf(t, nil, nil, "msg with args %d %s", 42, "42") + assert.Empty(t, err.Error()) + assert.Emptyf(t, err.Error(), "msg with args %d %s", 42, "42") + assert.NotEmpty(t, err.Error()) + assert.NotEmptyf(t, err.Error(), "msg with args %d %s", 42, "42") + assert.Zero(t, err.Error()) + assert.Zerof(t, err.Error(), "msg with args %d %s", 42, "42") + assert.NotZero(t, err.Error()) + assert.NotZerof(t, err.Error(), "msg with args %d %s", 42, "42") + assert.Nil(t, errs) + assert.Nilf(t, errs, "msg with args %d %s", 42, "42") + assert.NotNil(t, errs) + assert.NotNilf(t, errs, "msg with args %d %s", 42, "42") + assert.Empty(t, errs) + assert.Emptyf(t, errs, "msg with args %d %s", 42, "42") + assert.NotEmpty(t, errs) + assert.NotEmptyf(t, errs, "msg with args %d %s", 42, "42") + assert.Zero(t, errs) + assert.Zerof(t, errs, "msg with args %d %s", 42, "42") + assert.NotZero(t, errs) + assert.NotZerof(t, errs, "msg with args %d %s", 42, "42") } } diff --git a/internal/checkers/error_nil.go b/internal/checkers/error_nil.go index ef87d33b..b9f28df2 100644 --- a/internal/checkers/error_nil.go +++ b/internal/checkers/error_nil.go @@ -12,12 +12,16 @@ import ( // ErrorNil detects situations like // // assert.Nil(t, err) -// assert.NotNil(t, err) +// assert.Empty(t, err) +// assert.Zero(t, err) // assert.Equal(t, nil, err) // assert.EqualValues(t, nil, err) // assert.Exactly(t, nil, err) // assert.ErrorIs(t, err, nil) // +// assert.NotNil(t, err) +// assert.NotEmpty(t, err) +// assert.NotZero(t, err) // assert.NotEqual(t, nil, err) // assert.NotEqualValues(t, nil, err) // assert.NotErrorIs(t, err, nil) @@ -40,12 +44,12 @@ func (checker ErrorNil) Check(pass *analysis.Pass, call *CallMeta) *analysis.Dia proposedFn, survivingArg, replacementEndPos := func() (string, ast.Expr, token.Pos) { switch call.Fn.NameFTrimmed { - case "Nil": + case "Nil", "Empty", "Zero": if len(call.Args) >= 1 && isError(pass, call.Args[0]) { return noErrorFn, call.Args[0], call.Args[0].End() } - case "NotNil": + case "NotNil", "NotEmpty", "NotZero": if len(call.Args) >= 1 && isError(pass, call.Args[0]) { return errorFn, call.Args[0], call.Args[0].End() } diff --git a/internal/testgen/gen_error_nil.go b/internal/testgen/gen_error_nil.go index 75168a64..f8bf4c89 100644 --- a/internal/testgen/gen_error_nil.go +++ b/internal/testgen/gen_error_nil.go @@ -51,18 +51,23 @@ func (g ErrorNilTestsGenerator) TemplateData() any { }, InvalidAssertions: []Assertion{ {Fn: "Nil", Argsf: "err", ReportMsgf: report, ProposedFn: "NoError"}, - {Fn: "NotNil", Argsf: "err", ReportMsgf: report, ProposedFn: "Error"}, + {Fn: "Empty", Argsf: "err", ReportMsgf: report, ProposedFn: "NoError"}, + {Fn: "Zero", Argsf: "err", ReportMsgf: report, ProposedFn: "NoError"}, {Fn: "Equal", Argsf: "err, nil", ReportMsgf: report, ProposedFn: "NoError", ProposedArgsf: "err"}, {Fn: "Equal", Argsf: "nil, err", ReportMsgf: report, ProposedFn: "NoError", ProposedArgsf: "err"}, {Fn: "EqualValues", Argsf: "err, nil", ReportMsgf: report, ProposedFn: "NoError", ProposedArgsf: "err"}, {Fn: "EqualValues", Argsf: "nil, err", ReportMsgf: report, ProposedFn: "NoError", ProposedArgsf: "err"}, {Fn: "Exactly", Argsf: "err, nil", ReportMsgf: report, ProposedFn: "NoError", ProposedArgsf: "err"}, {Fn: "Exactly", Argsf: "nil, err", ReportMsgf: report, ProposedFn: "NoError", ProposedArgsf: "err"}, + {Fn: "ErrorIs", Argsf: "err, nil", ReportMsgf: report, ProposedFn: "NoError", ProposedArgsf: "err"}, + + {Fn: "NotNil", Argsf: "err", ReportMsgf: report, ProposedFn: "Error"}, + {Fn: "NotEmpty", Argsf: "err", ReportMsgf: report, ProposedFn: "Error"}, + {Fn: "NotZero", Argsf: "err", ReportMsgf: report, ProposedFn: "Error"}, {Fn: "NotEqual", Argsf: "err, nil", ReportMsgf: report, ProposedFn: "Error", ProposedArgsf: "err"}, {Fn: "NotEqual", Argsf: "nil, err", ReportMsgf: report, ProposedFn: "Error", ProposedArgsf: "err"}, {Fn: "NotEqualValues", Argsf: "err, nil", ReportMsgf: report, ProposedFn: "Error", ProposedArgsf: "err"}, {Fn: "NotEqualValues", Argsf: "nil, err", ReportMsgf: report, ProposedFn: "Error", ProposedArgsf: "err"}, - {Fn: "ErrorIs", Argsf: "err, nil", ReportMsgf: report, ProposedFn: "NoError", ProposedArgsf: "err"}, {Fn: "NotErrorIs", Argsf: "err, nil", ReportMsgf: report, ProposedFn: "Error", ProposedArgsf: "err"}, }, ValidAssertions: []Assertion{ @@ -76,6 +81,18 @@ func (g ErrorNilTestsGenerator) TemplateData() any { {Fn: "Equal", Argsf: "nil, nil"}, {Fn: "NotEqual", Argsf: "err, err"}, {Fn: "NotEqual", Argsf: "nil, nil"}, + + {Fn: "Empty", Argsf: "err.Error()"}, + {Fn: "NotEmpty", Argsf: "err.Error()"}, + {Fn: "Zero", Argsf: "err.Error()"}, + {Fn: "NotZero", Argsf: "err.Error()"}, + + {Fn: "Nil", Argsf: "errs"}, + {Fn: "NotNil", Argsf: "errs"}, + {Fn: "Empty", Argsf: "errs"}, + {Fn: "NotEmpty", Argsf: "errs"}, + {Fn: "Zero", Argsf: "errs"}, + {Fn: "NotZero", Argsf: "errs"}, }, } } @@ -106,6 +123,7 @@ import ( func {{ .CheckerName.AsTestName }}(t *testing.T) { var err error + var errs []error // Invalid. {