-
Notifications
You must be signed in to change notification settings - Fork 298
Add redundant-test-main-exit rule #1208
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
Changes from 1 commit
0de14d7
a845971
ecc514d
af68385
0c43b09
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package rule | ||
|
||
import ( | ||
"fmt" | ||
"go/ast" | ||
|
||
"github.com/mgechev/revive/lint" | ||
) | ||
|
||
// RedundantTestMainExitRule suggests removing Exit call in TestMain function for test files. | ||
type RedundantTestMainExitRule struct{} | ||
|
||
// Apply applies the rule to given file. | ||
func (*RedundantTestMainExitRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure { | ||
var failures []lint.Failure | ||
|
||
onFailure := func(failure lint.Failure) { | ||
failures = append(failures, failure) | ||
} | ||
|
||
w := &lintRedundantTestMainExit{onFailure: onFailure, isTestFile: file.IsTest()} | ||
ast.Walk(w, file.AST) | ||
return failures | ||
} | ||
|
||
// Name returns the rule name. | ||
func (*RedundantTestMainExitRule) Name() string { | ||
return "redundant-test-main-exit" | ||
} | ||
|
||
type lintRedundantTestMainExit struct { | ||
onFailure func(lint.Failure) | ||
isTestFile bool | ||
semihbkgr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
func (w *lintRedundantTestMainExit) Visit(node ast.Node) ast.Visitor { | ||
if !w.isTestFile { | ||
return nil // skip analysis of this file if it is not a test file | ||
} | ||
|
||
se, ok := node.(*ast.ExprStmt) | ||
if !ok { | ||
return w | ||
} | ||
ce, ok := se.X.(*ast.CallExpr) | ||
if !ok { | ||
return w | ||
} | ||
|
||
fc, ok := ce.Fun.(*ast.SelectorExpr) | ||
if !ok { | ||
return w | ||
} | ||
id, ok := fc.X.(*ast.Ident) | ||
if !ok { | ||
return w | ||
} | ||
|
||
pkg := id.Name | ||
fn := fc.Sel.Name | ||
if isCallToExitFunction(pkg, fn) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @chavacava, thank you for your detailed review and suggestions! I’m not entirely sure about including logging functions other than What’s your opinion on this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The issue with including logging functions is that the common failure message may not be appropriate for them, as these functions are not necessarily redundant: they first log a message and then exit. |
||
w.onFailure(lint.Failure{ | ||
Confidence: 1, | ||
Node: ce, | ||
Category: lint.FailureCategoryBadPractice, | ||
chavacava marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Failure: fmt.Sprintf("redundant call to %s.%s in TestMain function, the test runner will handle it automatically as of Go 1.15", pkg, fn), | ||
}) | ||
} | ||
|
||
return w | ||
} | ||
|
||
func (w *lintRedundantTestMainExit) isTestMain(fd *ast.FuncDecl) bool { | ||
semihbkgr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return w.isTestFile && fd.Name.Name == "TestMain" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/mgechev/revive/rule" | ||
) | ||
|
||
func TestRedundantTestMainExit(t *testing.T) { | ||
testRule(t, "redundant_test_main_exit_test", &rule.RedundantTestMainExitRule{}) | ||
testRule(t, "redundant_test_main_exit", &rule.RedundantTestMainExitRule{}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package fixtures | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"testing" | ||
) | ||
|
||
func TestMain(m *testing.M) { | ||
setup() | ||
i := m.Run() | ||
teardown() | ||
// must not match because this is not a test file | ||
os.Exit(i) | ||
} | ||
|
||
func setup() { | ||
fmt.Println("Setup") | ||
} | ||
|
||
func teardown() { | ||
fmt.Println("Teardown") | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package fixtures | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"syscall" | ||
"testing" | ||
) | ||
|
||
func TestMain(m *testing.M) { | ||
setup() | ||
i := m.Run() | ||
teardown() | ||
os.Exit(i) // MATCH /redundant call to os.Exit in TestMain function, the test runner will handle it automatically as of Go 1.15/ | ||
syscall.Exit(i) // MATCH /redundant call to syscall.Exit in TestMain function, the test runner will handle it automatically as of Go 1.15/ | ||
} | ||
|
||
func setup() { | ||
fmt.Println("Setup") | ||
} | ||
|
||
func teardown() { | ||
fmt.Println("Teardown") | ||
} | ||
|
||
func Test_function(t *testing.T) { | ||
t.Error("Fail") | ||
} |
Uh oh!
There was an error while loading. Please reload this page.