Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor ginkgo handler #166

Merged
merged 2 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions internal/expression/actual/asyncfuncarg.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package actual

import (
"github.com/nunnatsa/ginkgolinter/internal/gomegahandler"
"github.com/nunnatsa/ginkgolinter/internal/interfaces"
gotypes "go/types"

"github.com/nunnatsa/ginkgolinter/internal/gomegainfo"
"github.com/nunnatsa/ginkgolinter/internal/interfaces"
)

func getAsyncFuncArg(sig *gotypes.Signature) ArgPayload {
Expand All @@ -16,7 +17,7 @@ func getAsyncFuncArg(sig *gotypes.Signature) ArgPayload {

if sig.Params().Len() > 0 {
arg := sig.Params().At(0).Type()
if gomegahandler.IsGomegaType(arg) && sig.Results().Len() == 0 {
if gomegainfo.IsGomegaType(arg) && sig.Results().Len() == 0 {
argType |= FuncSigArgType | GomegaParamArgType
}
}
Expand Down
36 changes: 36 additions & 0 deletions internal/ginkgohandler/dothandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package ginkgohandler

import (
"go/ast"

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

"github.com/nunnatsa/ginkgolinter/types"
)

// dotHandler is used when importing ginkgo with dot; i.e.
// import . "github.com/onsi/ginkgo"
type dotHandler struct{}

func (h dotHandler) HandleGinkgoSpecs(expr ast.Expr, config types.Config, pass *analysis.Pass) bool {
return handleGinkgoSpecs(expr, config, pass, h)
}

func (h dotHandler) getFocusContainerName(exp *ast.CallExpr) (bool, *ast.Ident) {
if fun, ok := exp.Fun.(*ast.Ident); ok {
return isFocusContainer(fun.Name), fun
}
return false, nil
}

func (h dotHandler) isWrapContainer(exp *ast.CallExpr) bool {
if fun, ok := exp.Fun.(*ast.Ident); ok {
return isWrapContainer(fun.Name)
}
return false
}

func (h dotHandler) isFocusSpec(exp ast.Expr) bool {
id, ok := exp.(*ast.Ident)
return ok && id.Name == focusSpec
}
63 changes: 63 additions & 0 deletions internal/ginkgohandler/ginkgoinfo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package ginkgohandler

const ( // container names
describe = "Describe"
pdescribe = "PDescribe"
xdescribe = "XDescribe"
fdescribe = "FDescribe"

when = "When"
pwhen = "PWhen"
xwhen = "XWhen"
fwhen = "FWhen"

contextContainer = "Context"
pcontext = "PContext"
xcontext = "XContext"
fcontext = "FContext"

it = "It"
pit = "PIt"
xit = "XIt"
fit = "FIt"

describeTable = "DescribeTable"
pdescribeTable = "PDescribeTable"
xdescribeTable = "XDescribeTable"
fdescribeTable = "FDescribeTable"

entry = "Entry"
pentry = "PEntry"
xentry = "XEntry"
fentry = "FEntry"
)

func isFocusContainer(name string) bool {
switch name {
case fdescribe, fcontext, fwhen, fit, fdescribeTable, fentry:
return true
}
return false
}

func isContainer(name string) bool {
switch name {
case it, when, contextContainer, describe, describeTable, entry,
pit, pwhen, pcontext, pdescribe, pdescribeTable, pentry,
xit, xwhen, xcontext, xdescribe, xdescribeTable, xentry:
return true
}
return isFocusContainer(name)
}

func isWrapContainer(name string) bool {
switch name {
case when, contextContainer, describe,
fwhen, fcontext, fdescribe,
pwhen, pcontext, pdescribe,
xwhen, xcontext, xdescribe:
return true
}

return false
}
123 changes: 21 additions & 102 deletions internal/ginkgohandler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package ginkgohandler

import (
"go/ast"

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

"github.com/nunnatsa/ginkgolinter/types"
)

const (
Expand All @@ -14,116 +18,31 @@ const (
// Handler provide different handling, depend on the way ginkgo was imported, whether
// in imported with "." name, custom name or without any name.
type Handler interface {
GetFocusContainerName(*ast.CallExpr) (bool, *ast.Ident)
IsWrapContainer(*ast.CallExpr) bool
IsFocusSpec(ident ast.Expr) bool
HandleGinkgoSpecs(ast.Expr, types.Config, *analysis.Pass) bool
getFocusContainerName(*ast.CallExpr) (bool, *ast.Ident)
isWrapContainer(*ast.CallExpr) bool
isFocusSpec(ident ast.Expr) bool
}

// GetGinkgoHandler returns a ginkgor handler according to the way ginkgo was imported in the specific file
func GetGinkgoHandler(file *ast.File) Handler {
for _, imp := range file.Imports {
if imp.Path.Value != importPath && imp.Path.Value != importPathV2 {
continue
}
switch imp.Path.Value {

case importPath, importPathV2:
switch name := imp.Name.String(); {
case name == ".":
return dotHandler{}
case name == "<nil>": // import with no local name
return nameHandler("ginkgo")
default:
return nameHandler(name)
}

switch name := imp.Name.String(); {
case name == ".":
return dotHandler{}
case name == "<nil>": // import with no local name
return nameHandler("ginkgo")
default:
return nameHandler(name)
}
}

return nil // no ginkgo import; this file does not use ginkgo
}

// dotHandler is used when importing ginkgo with dot; i.e.
// import . "github.com/onsi/ginkgo"
type dotHandler struct{}

func (h dotHandler) GetFocusContainerName(exp *ast.CallExpr) (bool, *ast.Ident) {
if fun, ok := exp.Fun.(*ast.Ident); ok {
return isFocusContainer(fun.Name), fun
}
return false, nil
}

func (h dotHandler) IsWrapContainer(exp *ast.CallExpr) bool {
if fun, ok := exp.Fun.(*ast.Ident); ok {
return IsWrapContainer(fun.Name)
}
return false
}

func (h dotHandler) IsFocusSpec(exp ast.Expr) bool {
id, ok := exp.(*ast.Ident)
return ok && id.Name == focusSpec
}

// nameHandler is used when importing ginkgo without name; i.e.
// import "github.com/onsi/ginkgo"
//
// or with a custom name; e.g.
// import customname "github.com/onsi/ginkgo"
type nameHandler string

func (h nameHandler) GetFocusContainerName(exp *ast.CallExpr) (bool, *ast.Ident) {
if sel, ok := exp.Fun.(*ast.SelectorExpr); ok {
if id, ok := sel.X.(*ast.Ident); ok && id.Name == string(h) {
return isFocusContainer(sel.Sel.Name), sel.Sel
}
}
return false, nil
}

func (h nameHandler) IsWrapContainer(exp *ast.CallExpr) bool {
if sel, ok := exp.Fun.(*ast.SelectorExpr); ok {
if id, ok := sel.X.(*ast.Ident); ok && id.Name == string(h) {
return IsWrapContainer(sel.Sel.Name)
}
}
return false

}

func (h nameHandler) IsFocusSpec(exp ast.Expr) bool {
if selExp, ok := exp.(*ast.SelectorExpr); ok {
if x, ok := selExp.X.(*ast.Ident); ok && x.Name == string(h) {
return selExp.Sel.Name == focusSpec
continue
}
}

return false
}

func isFocusContainer(name string) bool {
switch name {
case "FDescribe", "FContext", "FWhen", "FIt", "FDescribeTable", "FEntry":
return true
}
return false
}

func IsContainer(name string) bool {
switch name {
case "It", "When", "Context", "Describe", "DescribeTable", "Entry",
"PIt", "PWhen", "PContext", "PDescribe", "PDescribeTable", "PEntry",
"XIt", "XWhen", "XContext", "XDescribe", "XDescribeTable", "XEntry":
return true
}
return isFocusContainer(name)
}

func IsWrapContainer(name string) bool {
switch name {
case "When", "Context", "Describe",
"FWhen", "FContext", "FDescribe",
"PWhen", "PContext", "PDescribe",
"XWhen", "XContext", "XDescribe":
return true
}

return false
return nil
}
32 changes: 16 additions & 16 deletions internal/ginkgohandler/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,38 +113,38 @@ func TestGetGinkgoHandler_no_ginkgo(t *testing.T) {

func TestDotHandler_GetFocusContainerName_happy(t *testing.T) {
exp := &ast.CallExpr{
Fun: ast.NewIdent("FIt"),
Fun: ast.NewIdent(fit),
}

h := dotHandler{}

isFocus, name := h.GetFocusContainerName(exp)
isFocus, name := h.getFocusContainerName(exp)

if !isFocus {
t.Error("h.GetFocusContainerName(exp) should return true")
}

if name == nil {
t.Error("should return valid ast.Ident object")
} else if name.Name != "FIt" {
} else if name.Name != fit {
t.Error("function name should be 'FIt'")
}
}

func TestDotHandler_GetFocusContainerName_no_focus(t *testing.T) {
exp := &ast.CallExpr{
Fun: ast.NewIdent("It"),
Fun: ast.NewIdent(it),
}

h := dotHandler{}
isFocus, name := h.GetFocusContainerName(exp)
isFocus, name := h.getFocusContainerName(exp)
if isFocus {
t.Error("h.GetFocusContainerName(exp) should return false")
}

if name == nil {
t.Error("should return valid ast.Ident object")
} else if name.Name != "It" {
} else if name.Name != it {
t.Error("function name should be 'It'")
}
}
Expand All @@ -154,13 +154,13 @@ func TestDotHandler_GetFocusContainerName_selector(t *testing.T) {
Fun: &ast.SelectorExpr{
Sel: ast.NewIdent("ginkgo"),
X: &ast.CallExpr{
Fun: ast.NewIdent("FIt"),
Fun: ast.NewIdent(fit),
},
},
}

h := dotHandler{}
isFocus, name := h.GetFocusContainerName(exp)
isFocus, name := h.getFocusContainerName(exp)
if isFocus {
t.Error("h.GetFocusContainerName(exp) should return false")
}
Expand All @@ -173,52 +173,52 @@ func TestDotHandler_GetFocusContainerName_selector(t *testing.T) {
func TestNameHandler_GetFocusContainerName_happy(t *testing.T) {
exp := &ast.CallExpr{
Fun: &ast.SelectorExpr{
Sel: ast.NewIdent("FIt"),
Sel: ast.NewIdent(fit),
X: ast.NewIdent("ginkgo"),
},
}

h := nameHandler("ginkgo")
isFocus, name := h.GetFocusContainerName(exp)
isFocus, name := h.getFocusContainerName(exp)
if !isFocus {
t.Error("h.GetFocusContainerName(exp) should return true")
}

if name == nil {
t.Error("should return a valid ast.Ident object")
} else if name.Name != "FIt" {
} else if name.Name != fit {
t.Error("function name should be 'FIt'")
}
}

func TestNameHandler_GetFocusContainerName_no_focus(t *testing.T) {
exp := &ast.CallExpr{
Fun: &ast.SelectorExpr{
Sel: ast.NewIdent("It"),
Sel: ast.NewIdent(it),
X: ast.NewIdent("ginkgo"),
},
}

h := nameHandler("ginkgo")
isFocus, name := h.GetFocusContainerName(exp)
isFocus, name := h.getFocusContainerName(exp)
if isFocus {
t.Error("h.GetFocusContainerName(exp) should return false")
}

if name == nil {
t.Error("should return a valid ast.Ident object")
} else if name.Name != "It" {
} else if name.Name != it {
t.Error("function name should be 'FIt'")
}
}

func TestNameHandler_GetFocusContainerName_ident(t *testing.T) {
exp := &ast.CallExpr{
Fun: ast.NewIdent("FIt"),
Fun: ast.NewIdent(fit),
}

h := nameHandler("ginkgo")
isFocus, name := h.GetFocusContainerName(exp)
isFocus, name := h.getFocusContainerName(exp)
if isFocus {
t.Error("h.GetFocusContainerName(exp) should return false")
}
Expand Down
Loading
Loading