Skip to content

Commit 22fcadb

Browse files
committed
Support gomega without ginkgo
This PR adds support for cases when using gomega directly, without ginkgo. For example: g := NewGomegaWithT(t) var err error g.Expect(err).ToNot(BeNil())
1 parent 2127a1e commit 22fcadb

File tree

6 files changed

+263
-11
lines changed

6 files changed

+263
-11
lines changed

.github/workflows/sanity.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ jobs:
4141
cp ginkgolinter testdata/src/a
4242
cd testdata/src/a
4343
44-
[[ $(./ginkgolinter ./... 2>&1 | wc -l) == 2074 ]]
44+
[[ $(./ginkgolinter ./... 2>&1 | wc -l) == 2095 ]]
4545
[[ $(./ginkgolinter --suppress-len-assertion=true --suppress-err-assertion=true ./... 2>&1 | wc -l) == 1363 ]]
46-
[[ $(./ginkgolinter --suppress-nil-assertion=true --suppress-err-assertion=true ./... 2>&1 | wc -l) == 617 ]]
47-
[[ $(./ginkgolinter --suppress-nil-assertion=true --suppress-len-assertion=true ./... 2>&1 | wc -l) == 100 ]]
46+
[[ $(./ginkgolinter --suppress-nil-assertion=true --suppress-err-assertion=true ./... 2>&1 | wc -l) == 620 ]]
47+
[[ $(./ginkgolinter --suppress-nil-assertion=true --suppress-len-assertion=true ./... 2>&1 | wc -l) == 118 ]]
4848
[[ $(./ginkgolinter --suppress-nil-assertion=true --suppress-len-assertion=true --suppress-err-assertion=true ./... 2>&1 | wc -l) == 0 ]]

ginkgo_linter_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,7 @@ func TestNoDotImport(t *testing.T) {
107107
func TestErrNil(t *testing.T) {
108108
analysistest.Run(t, analysistest.TestData(), ginkgolinter.NewAnalyzer(), "a/errnil")
109109
}
110+
111+
func TestGomegaOnly(t *testing.T) {
112+
analysistest.Run(t, analysistest.TestData(), ginkgolinter.NewAnalyzer(), "a/gomegaonly")
113+
}

gomegahandler/handler.go

Lines changed: 96 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package gomegahandler
22

3-
import "go/ast"
3+
import (
4+
"go/ast"
5+
"go/token"
6+
)
47

58
// Handler provide different handling, depend on the way gomega was imported, whether
69
// in imported with "." name, custom name or without any name.
@@ -9,6 +12,10 @@ type Handler interface {
912
GetActualFuncName(*ast.CallExpr) (string, bool)
1013
// ReplaceFunction replaces the function with another one, for fix suggestions
1114
ReplaceFunction(*ast.CallExpr, *ast.Ident)
15+
16+
getDefFuncName(expr *ast.CallExpr) string
17+
18+
getFieldType(field *ast.Field) string
1219
}
1320

1421
// GetGomegaHandler returns a gomegar handler according to the way gomega was imported in the specific file
@@ -36,20 +43,45 @@ func GetGomegaHandler(file *ast.File) Handler {
3643
type dotHandler struct{}
3744

3845
// GetActualFuncName returns the name of the gomega function, e.g. `Expect`
39-
func (dotHandler) GetActualFuncName(expr *ast.CallExpr) (string, bool) {
40-
actualFunc, ok := expr.Fun.(*ast.Ident)
41-
if !ok {
42-
return "", false
46+
func (h dotHandler) GetActualFuncName(expr *ast.CallExpr) (string, bool) {
47+
switch actualFunc := expr.Fun.(type) {
48+
case *ast.Ident:
49+
return actualFunc.Name, true
50+
case *ast.SelectorExpr:
51+
if isGomegaVar(actualFunc.X, h) {
52+
return actualFunc.Sel.Name, true
53+
}
4354
}
44-
45-
return actualFunc.Name, true
55+
return "", false
4656
}
4757

4858
// ReplaceFunction replaces the function with another one, for fix suggestions
4959
func (dotHandler) ReplaceFunction(caller *ast.CallExpr, newExpr *ast.Ident) {
5060
caller.Fun = newExpr
5161
}
5262

63+
func (dotHandler) getDefFuncName(expr *ast.CallExpr) string {
64+
if f, ok := expr.Fun.(*ast.Ident); ok {
65+
return f.Name
66+
}
67+
return ""
68+
}
69+
70+
func (dotHandler) getFieldType(field *ast.Field) string {
71+
switch t := field.Type.(type) {
72+
case *ast.Ident:
73+
return t.Name
74+
case *ast.StarExpr:
75+
if name, ok := t.X.(*ast.Ident); ok {
76+
return name.Name
77+
}
78+
}
79+
if id, ok := field.Type.(*ast.Ident); ok {
80+
return id.Name
81+
}
82+
return ""
83+
}
84+
5385
// nameHandler is used when importing gomega without name; i.e.
5486
// import "github.com/onsi/gomega"
5587
//
@@ -70,7 +102,9 @@ func (g nameHandler) GetActualFuncName(expr *ast.CallExpr) (string, bool) {
70102
}
71103

72104
if x.Name != string(g) {
73-
return "", false
105+
if !isGomegaVar(x, g) {
106+
return "", false
107+
}
74108
}
75109

76110
return selector.Sel.Name, true
@@ -80,3 +114,57 @@ func (g nameHandler) GetActualFuncName(expr *ast.CallExpr) (string, bool) {
80114
func (nameHandler) ReplaceFunction(caller *ast.CallExpr, newExpr *ast.Ident) {
81115
caller.Fun.(*ast.SelectorExpr).Sel = newExpr
82116
}
117+
118+
func (g nameHandler) getDefFuncName(expr *ast.CallExpr) string {
119+
if sel, ok := expr.Fun.(*ast.SelectorExpr); ok {
120+
if f, ok := sel.X.(*ast.Ident); ok && f.Name == string(g) {
121+
return sel.Sel.Name
122+
}
123+
}
124+
return ""
125+
}
126+
127+
func (g nameHandler) getFieldType(field *ast.Field) string {
128+
switch t := field.Type.(type) {
129+
case *ast.SelectorExpr:
130+
if id, ok := t.X.(*ast.Ident); ok {
131+
if id.Name == string(g) {
132+
return t.Sel.Name
133+
}
134+
}
135+
case *ast.StarExpr:
136+
if sel, ok := t.X.(*ast.SelectorExpr); ok {
137+
if x, ok := sel.X.(*ast.Ident); ok && x.Name == string(g) {
138+
return sel.Sel.Name
139+
}
140+
}
141+
142+
}
143+
return ""
144+
}
145+
146+
func isGomegaVar(x ast.Expr, handler Handler) bool {
147+
if i, ok := x.(*ast.Ident); ok {
148+
if i.Obj != nil && i.Obj.Kind == ast.Var {
149+
switch decl := i.Obj.Decl.(type) {
150+
case *ast.AssignStmt:
151+
if decl.Tok == token.DEFINE {
152+
if defFunc, ok := decl.Rhs[0].(*ast.CallExpr); ok {
153+
fName := handler.getDefFuncName(defFunc)
154+
switch fName {
155+
case "NewGomega", "NewWithT", "NewGomegaWithT":
156+
return true
157+
}
158+
}
159+
}
160+
case *ast.Field:
161+
name := handler.getFieldType(decl)
162+
switch name {
163+
case "Gomega", "WithT", "GomegaWithT":
164+
return true
165+
}
166+
}
167+
}
168+
}
169+
return false
170+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package gomegaonly
2+
3+
import (
4+
"testing"
5+
6+
. "github.com/onsi/ginkgo/v2"
7+
. "github.com/onsi/gomega"
8+
)
9+
10+
func TestGomegaOnly_NewGomegaWithT(t *testing.T) {
11+
g := NewGomegaWithT(t)
12+
13+
var err error
14+
g.Expect(err).ToNot(BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.To\(HaveOccurred\(\)\). instead`
15+
assert(g, err)
16+
assertWithT(g, err)
17+
assertGomegaWithT(g, err)
18+
}
19+
20+
func assert(g Gomega, err error) {
21+
g.Expect(err).To(BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.ToNot\(HaveOccurred\(\)\). instead`
22+
}
23+
24+
func assertWithT(g *WithT, err error) {
25+
g.Expect(err).To(BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.ToNot\(HaveOccurred\(\)\). instead`
26+
}
27+
28+
func assertGomegaWithT(g *GomegaWithT, err error) {
29+
g.Expect(err).To(BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.ToNot\(HaveOccurred\(\)\). instead`
30+
}
31+
32+
func TestGomegaOnly_NewWithT(t *testing.T) {
33+
g := NewWithT(t)
34+
35+
var err error
36+
g.Expect(err).ToNot(BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.To\(HaveOccurred\(\)\). instead`
37+
assert(g, err)
38+
}
39+
40+
func TestGomegaOnly_NewGomega(t *testing.T) {
41+
g := NewGomega(Fail)
42+
43+
var err error
44+
g.Expect(err).ToNot(BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.To\(HaveOccurred\(\)\). instead`
45+
assert(g, err)
46+
}
47+
48+
var _ = Describe("check gomega parameter", func() {
49+
Eventually(func(g Gomega) error {
50+
arr := []int{1, 2, 3}
51+
g.Expect(len(arr)).Should(Equal(3)) // want `ginkgo-linter: wrong length assertion; consider using .g\.Expect\(arr\)\.Should\(HaveLen\(3\)\). instead`
52+
return nil
53+
}).Should(Succeed())
54+
})
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package gomegaonly
2+
3+
import (
4+
"testing"
5+
6+
. "github.com/onsi/ginkgo/v2"
7+
gom "github.com/onsi/gomega"
8+
)
9+
10+
func TestGomegaOnlyWithModName_NewGomegaWithT(t *testing.T) {
11+
g := gom.NewGomegaWithT(t)
12+
13+
var err error
14+
g.Expect(err).ToNot(gom.BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.To\(gom.HaveOccurred\(\)\). instead`
15+
16+
assertWithModName(g, err)
17+
assertWithNameModWithT(g, err)
18+
assertWithModNameGomegaWithT(g, err)
19+
}
20+
21+
func TestGomegaOnlyWithModName_NewWithT(t *testing.T) {
22+
g := gom.NewWithT(t)
23+
24+
var err error
25+
g.Expect(err).ToNot(gom.BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.To\(gom.HaveOccurred\(\)\). instead`
26+
}
27+
28+
func TestGomegaOnlyWithModName_NewGomega(t *testing.T) {
29+
g := gom.NewGomega(Fail)
30+
31+
var err error
32+
g.Expect(err).ToNot(gom.BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.To\(gom.HaveOccurred\(\)\). instead`
33+
}
34+
35+
func assertWithModName(g gom.Gomega, err error) {
36+
g.Expect(err).To(gom.BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.ToNot\(gom\.HaveOccurred\(\)\). instead`
37+
}
38+
39+
func assertWithNameModWithT(g *gom.WithT, err error) {
40+
g.Expect(err).To(gom.BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.ToNot\(gom\.HaveOccurred\(\)\). instead`
41+
}
42+
43+
func assertWithModNameGomegaWithT(g *gom.WithT, err error) {
44+
g.Expect(err).To(gom.BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.ToNot\(gom\.HaveOccurred\(\)\). instead`
45+
}
46+
47+
var _ = Describe("check gomega parameter", func() {
48+
gom.Eventually(func(g gom.Gomega) error {
49+
arr := []int{1, 2, 3}
50+
g.Expect(len(arr)).Should(gom.Equal(3)) // want `ginkgo-linter: wrong length assertion; consider using .g\.Expect\(arr\)\.Should\(gom\.HaveLen\(3\)\). instead`
51+
return nil
52+
}).Should(gom.Succeed())
53+
})
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package gomegaonly
2+
3+
import (
4+
"testing"
5+
6+
. "github.com/onsi/ginkgo/v2"
7+
"github.com/onsi/gomega"
8+
)
9+
10+
func TestGomegaOnlyWithName_NewGomegaWithT(t *testing.T) {
11+
g := gomega.NewGomegaWithT(t)
12+
13+
var err error
14+
g.Expect(err).ToNot(gomega.BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.To\(gomega.HaveOccurred\(\)\). instead`
15+
16+
assertWithName(g, err)
17+
assertWithNameWithT(g, err)
18+
assertWithNameGomegaWithT(g, err)
19+
}
20+
21+
func TestGomegaOnlyWithName_NewWithT(t *testing.T) {
22+
g := gomega.NewWithT(t)
23+
24+
var err error
25+
g.Expect(err).ToNot(gomega.BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.To\(gomega.HaveOccurred\(\)\). instead`
26+
}
27+
28+
func TestGomegaOnlyWithName_NewGomega(t *testing.T) {
29+
g := gomega.NewGomega(Fail)
30+
31+
var err error
32+
g.Expect(err).ToNot(gomega.BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.To\(gomega.HaveOccurred\(\)\). instead`
33+
}
34+
35+
func assertWithName(g gomega.Gomega, err error) {
36+
g.Expect(err).To(gomega.BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.ToNot\(gomega\.HaveOccurred\(\)\). instead`
37+
}
38+
39+
func assertWithNameWithT(g *gomega.WithT, err error) {
40+
g.Expect(err).To(gomega.BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.ToNot\(gomega\.HaveOccurred\(\)\). instead`
41+
}
42+
43+
func assertWithNameGomegaWithT(g *gomega.WithT, err error) {
44+
g.Expect(err).To(gomega.BeNil()) // want `ginkgo-linter: wrong error assertion; consider using .g\.Expect\(err\)\.ToNot\(gomega\.HaveOccurred\(\)\). instead`
45+
}
46+
47+
var _ = Describe("check gomega parameter", func() {
48+
gomega.Eventually(func(g gomega.Gomega) error {
49+
arr := []int{1, 2, 3}
50+
g.Expect(len(arr)).Should(gomega.Equal(3)) // want `ginkgo-linter: wrong length assertion; consider using .g\.Expect\(arr\)\.Should\(gomega\.HaveLen\(3\)\). instead`
51+
return nil
52+
}).Should(gomega.Succeed())
53+
})

0 commit comments

Comments
 (0)