Skip to content

Commit a6e65e3

Browse files
authored
introduce helpers_*.go files (#92)
* introduce helpers_*.go files * cosmetis
1 parent bff320f commit a6e65e3

31 files changed

+647
-569
lines changed

CONTRIBUTING.md

+2
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ Remember that [assert.TestingT](https://pkg.go.dev/github.com/stretchr/testify/a
9999
[require.TestingT](https://pkg.go.dev/github.com/stretchr/testify/require#TestingT) are different interfaces,
100100
which may be important in some contexts.
101101

102+
Also, pay attention to `internal/checkers/helpers_*.go` files. Try to reuse existing code as much as possible.
103+
102104
### 8) Improve tests from p.4 if necessary
103105

104106
Pay attention to `Assertion` and `NewAssertionExpander`, but keep your tests as small as possible.

internal/checkers/bool_compare.go

-92
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package checkers
33
import (
44
"go/ast"
55
"go/token"
6-
"go/types"
76

87
"golang.org/x/tools/go/analysis"
98

@@ -204,101 +203,10 @@ func (checker BoolCompare) Check(pass *analysis.Pass, call *CallMeta) *analysis.
204203
return nil
205204
}
206205

207-
func isEmptyInterface(pass *analysis.Pass, expr ast.Expr) bool {
208-
t, ok := pass.TypesInfo.Types[expr]
209-
if !ok {
210-
return false
211-
}
212-
213-
iface, ok := t.Type.Underlying().(*types.Interface)
214-
return ok && iface.NumMethods() == 0
215-
}
216-
217-
func isBuiltinBool(pass *analysis.Pass, e ast.Expr) bool {
218-
basicType, ok := pass.TypesInfo.TypeOf(e).(*types.Basic)
219-
return ok && basicType.Kind() == types.Bool
220-
}
221-
222-
func isBoolOverride(pass *analysis.Pass, e ast.Expr) bool {
223-
namedType, ok := pass.TypesInfo.TypeOf(e).(*types.Named)
224-
return ok && namedType.Obj().Name() == "bool"
225-
}
226-
227-
var (
228-
falseObj = types.Universe.Lookup("false")
229-
trueObj = types.Universe.Lookup("true")
230-
)
231-
232-
func isUntypedTrue(pass *analysis.Pass, e ast.Expr) bool {
233-
return analysisutil.IsObj(pass.TypesInfo, e, trueObj)
234-
}
235-
236-
func isUntypedFalse(pass *analysis.Pass, e ast.Expr) bool {
237-
return analysisutil.IsObj(pass.TypesInfo, e, falseObj)
238-
}
239-
240-
func isComparisonWithTrue(pass *analysis.Pass, e ast.Expr, op token.Token) (ast.Expr, bool) {
241-
return isComparisonWith(pass, e, isUntypedTrue, op)
242-
}
243-
244-
func isComparisonWithFalse(pass *analysis.Pass, e ast.Expr, op token.Token) (ast.Expr, bool) {
245-
return isComparisonWith(pass, e, isUntypedFalse, op)
246-
}
247-
248-
type predicate func(pass *analysis.Pass, e ast.Expr) bool
249-
250-
func isComparisonWith(pass *analysis.Pass, e ast.Expr, predicate predicate, op token.Token) (ast.Expr, bool) {
251-
be, ok := e.(*ast.BinaryExpr)
252-
if !ok {
253-
return nil, false
254-
}
255-
if be.Op != op {
256-
return nil, false
257-
}
258-
259-
t1, t2 := predicate(pass, be.X), predicate(pass, be.Y)
260-
if xor(t1, t2) {
261-
if t1 {
262-
return be.Y, true
263-
}
264-
return be.X, true
265-
}
266-
return nil, false
267-
}
268-
269206
func isNegation(e ast.Expr) (ast.Expr, bool) {
270207
ue, ok := e.(*ast.UnaryExpr)
271208
if !ok {
272209
return nil, false
273210
}
274211
return ue.X, ue.Op == token.NOT
275212
}
276-
277-
func xor(a, b bool) bool {
278-
return a != b
279-
}
280-
281-
// anyVal returns the first value[i] for which bools[i] is true.
282-
func anyVal[T any](bools []bool, vals ...T) (T, bool) {
283-
if len(bools) != len(vals) {
284-
panic("inconsistent usage of valOr") //nolint:forbidigo // Does not depend on the code being analyzed.
285-
}
286-
287-
for i, b := range bools {
288-
if b {
289-
return vals[i], true
290-
}
291-
}
292-
293-
var _default T
294-
return _default, false
295-
}
296-
297-
func anyCondSatisfaction(pass *analysis.Pass, p predicate, vals ...ast.Expr) bool {
298-
for _, v := range vals {
299-
if p(pass, v) {
300-
return true
301-
}
302-
}
303-
return false
304-
}

internal/checkers/call_meta.go

-22
Original file line numberDiff line numberDiff line change
@@ -119,25 +119,3 @@ func trimTArg(pass *analysis.Pass, args []ast.Expr) []ast.Expr {
119119
}
120120
return args
121121
}
122-
123-
func implementsTestingT(pass *analysis.Pass, arg ast.Expr) bool {
124-
return implementsAssertTestingT(pass, arg) || implementsRequireTestingT(pass, arg)
125-
}
126-
127-
func implementsAssertTestingT(pass *analysis.Pass, e ast.Expr) bool {
128-
assertTestingTObj := analysisutil.ObjectOf(pass.Pkg, testify.AssertPkgPath, "TestingT")
129-
return (assertTestingTObj != nil) && implements(pass, e, assertTestingTObj)
130-
}
131-
132-
func implementsRequireTestingT(pass *analysis.Pass, e ast.Expr) bool {
133-
requireTestingTObj := analysisutil.ObjectOf(pass.Pkg, testify.RequirePkgPath, "TestingT")
134-
return (requireTestingTObj != nil) && implements(pass, e, requireTestingTObj)
135-
}
136-
137-
func implements(pass *analysis.Pass, e ast.Expr, ifaceObj types.Object) bool {
138-
t := pass.TypesInfo.TypeOf(e)
139-
if t == nil {
140-
return false
141-
}
142-
return types.Implements(t, ifaceObj.Type().Underlying().(*types.Interface))
143-
}

internal/checkers/compares.go

-11
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
package checkers
22

33
import (
4-
"bytes"
54
"go/ast"
65
"go/token"
76

87
"golang.org/x/tools/go/analysis"
9-
10-
"github.com/Antonboom/testifylint/internal/analysisutil"
118
)
129

1310
// Compares detects situations like
@@ -86,11 +83,3 @@ var tokenToProposedFnInsteadOfFalse = map[token.Token]string{
8683
token.LSS: "GreaterOrEqual",
8784
token.LEQ: "Greater",
8885
}
89-
90-
// formatAsCallArgs joins a and b and return bytes like `a, b`.
91-
func formatAsCallArgs(pass *analysis.Pass, a, b ast.Node) []byte {
92-
return bytes.Join([][]byte{
93-
analysisutil.NodeBytes(pass.Fset, a),
94-
analysisutil.NodeBytes(pass.Fset, b),
95-
}, []byte(", "))
96-
}

internal/checkers/empty.go

-34
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package checkers
22

33
import (
4-
"fmt"
54
"go/ast"
65
"go/token"
7-
"go/types"
86

97
"golang.org/x/tools/go/analysis"
108

@@ -138,35 +136,3 @@ func (checker Empty) checkNotEmpty(pass *analysis.Pass, call *CallMeta) *analysi
138136
}
139137
return nil
140138
}
141-
142-
var lenObj = types.Universe.Lookup("len")
143-
144-
func isLenCallAndZero(pass *analysis.Pass, a, b ast.Expr) (ast.Expr, bool) {
145-
lenArg, ok := isBuiltinLenCall(pass, a)
146-
return lenArg, ok && isZero(b)
147-
}
148-
149-
func isBuiltinLenCall(pass *analysis.Pass, e ast.Expr) (ast.Expr, bool) {
150-
ce, ok := e.(*ast.CallExpr)
151-
if !ok {
152-
return nil, false
153-
}
154-
155-
if analysisutil.IsObj(pass.TypesInfo, ce.Fun, lenObj) && len(ce.Args) == 1 {
156-
return ce.Args[0], true
157-
}
158-
return nil, false
159-
}
160-
161-
func isZero(e ast.Expr) bool {
162-
return isIntNumber(e, 0)
163-
}
164-
165-
func isOne(e ast.Expr) bool {
166-
return isIntNumber(e, 1)
167-
}
168-
169-
func isIntNumber(e ast.Expr, v int) bool {
170-
bl, ok := e.(*ast.BasicLit)
171-
return ok && bl.Kind == token.INT && bl.Value == fmt.Sprintf("%d", v)
172-
}

internal/checkers/error_is_as.go

-24
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import (
66
"go/types"
77

88
"golang.org/x/tools/go/analysis"
9-
10-
"github.com/Antonboom/testifylint/internal/analysisutil"
119
)
1210

1311
// ErrorIsAs detects situations like
@@ -142,25 +140,3 @@ func (checker ErrorIsAs) Check(pass *analysis.Pass, call *CallMeta) *analysis.Di
142140
}
143141
return nil
144142
}
145-
146-
func isErrorsIsCall(pass *analysis.Pass, ce *ast.CallExpr) bool {
147-
return isErrorsPkgFnCall(pass, ce, "Is")
148-
}
149-
150-
func isErrorsAsCall(pass *analysis.Pass, ce *ast.CallExpr) bool {
151-
return isErrorsPkgFnCall(pass, ce, "As")
152-
}
153-
154-
func isErrorsPkgFnCall(pass *analysis.Pass, ce *ast.CallExpr, fn string) bool {
155-
se, ok := ce.Fun.(*ast.SelectorExpr)
156-
if !ok {
157-
return false
158-
}
159-
160-
errorsIsObj := analysisutil.ObjectOf(pass.Pkg, "errors", fn)
161-
if errorsIsObj == nil {
162-
return false
163-
}
164-
165-
return analysisutil.IsObj(pass.TypesInfo, se.Sel, errorsIsObj)
166-
}

internal/checkers/error_nil.go

-21
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package checkers
33
import (
44
"go/ast"
55
"go/token"
6-
"go/types"
76

87
"golang.org/x/tools/go/analysis"
98

@@ -91,23 +90,3 @@ func (checker ErrorNil) Check(pass *analysis.Pass, call *CallMeta) *analysis.Dia
9190
}
9291
return nil
9392
}
94-
95-
var (
96-
errorType = types.Universe.Lookup("error").Type()
97-
errorIface = errorType.Underlying().(*types.Interface)
98-
)
99-
100-
func isError(pass *analysis.Pass, expr ast.Expr) bool {
101-
t := pass.TypesInfo.TypeOf(expr)
102-
if t == nil {
103-
return false
104-
}
105-
106-
_, ok := t.Underlying().(*types.Interface)
107-
return ok && types.Implements(t, errorIface)
108-
}
109-
110-
func isNil(expr ast.Expr) bool {
111-
ident, ok := expr.(*ast.Ident)
112-
return ok && ident.Name == "nil"
113-
}

internal/checkers/expected_actual.go

-36
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package checkers
33
import (
44
"go/ast"
55
"go/token"
6-
"go/types"
76
"regexp"
87

98
"golang.org/x/tools/go/analysis"
@@ -178,38 +177,3 @@ func isExpectedValueFactory(pass *analysis.Pass, ce *ast.CallExpr, pattern *rege
178177
}
179178
return false
180179
}
181-
182-
func isBasicLit(e ast.Expr) bool {
183-
_, ok := e.(*ast.BasicLit)
184-
return ok
185-
}
186-
187-
func isUntypedConst(p *analysis.Pass, e ast.Expr) bool {
188-
t := p.TypesInfo.TypeOf(e)
189-
if t == nil {
190-
return false
191-
}
192-
193-
b, ok := t.(*types.Basic)
194-
return ok && b.Info()&types.IsUntyped > 0
195-
}
196-
197-
func isTypedConst(p *analysis.Pass, e ast.Expr) bool {
198-
tt, ok := p.TypesInfo.Types[e]
199-
return ok && tt.IsValue() && tt.Value != nil
200-
}
201-
202-
func isIdentNamedAsExpected(pattern *regexp.Regexp, e ast.Expr) bool {
203-
id, ok := e.(*ast.Ident)
204-
return ok && pattern.MatchString(id.Name)
205-
}
206-
207-
func isStructVarNamedAsExpected(pattern *regexp.Regexp, e ast.Expr) bool {
208-
s, ok := e.(*ast.SelectorExpr)
209-
return ok && isIdentNamedAsExpected(pattern, s.X)
210-
}
211-
212-
func isStructFieldNamedAsExpected(pattern *regexp.Regexp, e ast.Expr) bool {
213-
s, ok := e.(*ast.SelectorExpr)
214-
return ok && isIdentNamedAsExpected(pattern, s.Sel)
215-
}

internal/checkers/float_compare.go

+2-22
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ package checkers
22

33
import (
44
"fmt"
5-
"go/ast"
65
"go/token"
7-
"go/types"
86

97
"golang.org/x/tools/go/analysis"
108
)
@@ -33,10 +31,10 @@ func (checker FloatCompare) Check(pass *analysis.Pass, call *CallMeta) *analysis
3331
return len(call.Args) > 1 && (isFloat(pass, call.Args[0]) || isFloat(pass, call.Args[1]))
3432

3533
case "True":
36-
return len(call.Args) > 0 && isFloatCompare(pass, call.Args[0], token.EQL)
34+
return len(call.Args) > 0 && isComparisonWithFloat(pass, call.Args[0], token.EQL)
3735

3836
case "False":
39-
return len(call.Args) > 0 && isFloatCompare(pass, call.Args[0], token.NEQ)
37+
return len(call.Args) > 0 && isComparisonWithFloat(pass, call.Args[0], token.NEQ)
4038
}
4139
return false
4240
}()
@@ -50,21 +48,3 @@ func (checker FloatCompare) Check(pass *analysis.Pass, call *CallMeta) *analysis
5048
}
5149
return nil
5250
}
53-
54-
func isFloat(pass *analysis.Pass, expr ast.Expr) bool {
55-
t := pass.TypesInfo.TypeOf(expr)
56-
if t == nil {
57-
return false
58-
}
59-
60-
bt, ok := t.Underlying().(*types.Basic)
61-
return ok && (bt.Info()&types.IsFloat > 0)
62-
}
63-
64-
func isFloatCompare(p *analysis.Pass, e ast.Expr, op token.Token) bool {
65-
be, ok := e.(*ast.BinaryExpr)
66-
if !ok {
67-
return false
68-
}
69-
return be.Op == op && (isFloat(p, be.X) || isFloat(p, be.Y))
70-
}

0 commit comments

Comments
 (0)