mirror of
https://github.com/mgechev/revive.git
synced 2025-04-21 11:56:55 +02:00
Add extra rule
This commit is contained in:
parent
bd04af7465
commit
b5fc0eaffc
4
fixtures/lint-file-header1.go
Normal file
4
fixtures/lint-file-header1.go
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// baz baz qux
|
||||||
|
// foobar
|
||||||
|
|
||||||
|
package fixtures
|
4
fixtures/lint-file-header2.go
Normal file
4
fixtures/lint-file-header2.go
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/* baz baz qux
|
||||||
|
foobar */
|
||||||
|
|
||||||
|
package fixtures
|
4
fixtures/lint-file-header3.go
Normal file
4
fixtures/lint-file-header3.go
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// baz baz qux
|
||||||
|
// qux foo
|
||||||
|
|
||||||
|
package fixtures // MATCH /the file doesn't have an appropriate header/
|
3
fixtures/lint-file-header4.go
Normal file
3
fixtures/lint-file-header4.go
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// foobar
|
||||||
|
|
||||||
|
package fixtures
|
4
fixtures/lint-file-header5.go
Normal file
4
fixtures/lint-file-header5.go
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// foobaz qux
|
||||||
|
// bar
|
||||||
|
|
||||||
|
package fixtures
|
86
rule/file-header.go
Normal file
86
rule/file-header.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package rule
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/mgechev/revive/lint"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FileHeaderRule lints given else constructs.
|
||||||
|
type FileHeaderRule struct{}
|
||||||
|
|
||||||
|
// Apply applies the rule to given file.
|
||||||
|
func (r *FileHeaderRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
|
||||||
|
var failures []lint.Failure
|
||||||
|
|
||||||
|
header, ok := arguments[0].(string)
|
||||||
|
if !ok {
|
||||||
|
panic("Invalid argument to the FileHeaderRule")
|
||||||
|
}
|
||||||
|
|
||||||
|
regex, err := regexp.Compile(header)
|
||||||
|
if err != nil {
|
||||||
|
panic(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
fileAst := file.AST
|
||||||
|
walker := lintFileHeader{
|
||||||
|
file: file,
|
||||||
|
fileAst: fileAst,
|
||||||
|
regex: regex,
|
||||||
|
onFailure: func(failure lint.Failure) {
|
||||||
|
failures = append(failures, failure)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ast.Walk(walker, fileAst)
|
||||||
|
|
||||||
|
return failures
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the rule name.
|
||||||
|
func (r *FileHeaderRule) Name() string {
|
||||||
|
return "file-header"
|
||||||
|
}
|
||||||
|
|
||||||
|
type lintFileHeader struct {
|
||||||
|
file *lint.File
|
||||||
|
fileAst *ast.File
|
||||||
|
regex *regexp.Regexp
|
||||||
|
onFailure func(lint.Failure)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w lintFileHeader) Visit(n ast.Node) ast.Visitor {
|
||||||
|
g := w.fileAst.Comments[0]
|
||||||
|
failure := lint.Failure{
|
||||||
|
Node: w.fileAst,
|
||||||
|
Confidence: 1,
|
||||||
|
Failure: "the file doesn't have an appropriate header",
|
||||||
|
}
|
||||||
|
if g == nil {
|
||||||
|
w.onFailure(failure)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
multi := regexp.MustCompile("^/\\*")
|
||||||
|
single := regexp.MustCompile("^//")
|
||||||
|
comment := ""
|
||||||
|
for _, c := range g.List {
|
||||||
|
text := c.Text
|
||||||
|
if multi.Match([]byte(text)) {
|
||||||
|
text = text[2 : len(text)-2]
|
||||||
|
} else if single.Match([]byte(text)) {
|
||||||
|
text = text[2:]
|
||||||
|
}
|
||||||
|
comment += text
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("#############")
|
||||||
|
fmt.Println(comment)
|
||||||
|
fmt.Println("#############")
|
||||||
|
if !w.regex.Match([]byte(comment)) {
|
||||||
|
w.onFailure(failure)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
17
test/cyclomatic_test.go
Normal file
17
test/cyclomatic_test.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mgechev/revive/lint"
|
||||||
|
"github.com/mgechev/revive/rule"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCyclomatic(t *testing.T) {
|
||||||
|
testRule(t, "cyclomatic", &rule.CyclomaticRule{}, &lint.RuleConfig{
|
||||||
|
Arguments: []interface{}{int64(1)},
|
||||||
|
})
|
||||||
|
testRule(t, "cyclomatic-2", &rule.CyclomaticRule{}, &lint.RuleConfig{
|
||||||
|
Arguments: []interface{}{int64(3)},
|
||||||
|
})
|
||||||
|
}
|
30
test/file-header_test.go
Normal file
30
test/file-header_test.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mgechev/revive/lint"
|
||||||
|
"github.com/mgechev/revive/rule"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLintFileHeader(t *testing.T) {
|
||||||
|
testRule(t, "lint-file-header1", &rule.FileHeaderRule{}, &lint.RuleConfig{
|
||||||
|
Arguments: []interface{}{"foobar"},
|
||||||
|
})
|
||||||
|
|
||||||
|
testRule(t, "lint-file-header2", &rule.FileHeaderRule{}, &lint.RuleConfig{
|
||||||
|
Arguments: []interface{}{"foobar"},
|
||||||
|
})
|
||||||
|
|
||||||
|
testRule(t, "lint-file-header3", &rule.FileHeaderRule{}, &lint.RuleConfig{
|
||||||
|
Arguments: []interface{}{"foobar"},
|
||||||
|
})
|
||||||
|
|
||||||
|
testRule(t, "lint-file-header4", &rule.FileHeaderRule{}, &lint.RuleConfig{
|
||||||
|
Arguments: []interface{}{"^\\sfoobar$"},
|
||||||
|
})
|
||||||
|
|
||||||
|
testRule(t, "lint-file-header5", &rule.FileHeaderRule{}, &lint.RuleConfig{
|
||||||
|
Arguments: []interface{}{"^\\sfoo.*bar$"},
|
||||||
|
})
|
||||||
|
}
|
@ -1,12 +1,4 @@
|
|||||||
// Copyright (c) 2013 The Go Authors. All rights reserved.
|
package test
|
||||||
//
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file or at
|
|
||||||
// https://developers.google.com/open-source/licenses/bsd.
|
|
||||||
|
|
||||||
// The code contains changes from the original source.
|
|
||||||
|
|
||||||
package testutil
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
@ -56,21 +48,6 @@ var rules = []lint.Rule{
|
|||||||
&rule.ContextArgumentsRule{},
|
&rule.ContextArgumentsRule{},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCyclomatic(t *testing.T) {
|
|
||||||
testRule(t, "cyclomatic", &rule.CyclomaticRule{}, &lint.RuleConfig{
|
|
||||||
Arguments: []interface{}{int64(1)},
|
|
||||||
})
|
|
||||||
testRule(t, "cyclomatic-2", &rule.CyclomaticRule{}, &lint.RuleConfig{
|
|
||||||
Arguments: []interface{}{int64(3)},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMaxPublicStructs(t *testing.T) {
|
|
||||||
testRule(t, "max-public-structs", &rule.MaxPublicStructsRule{}, &lint.RuleConfig{
|
|
||||||
Arguments: []interface{}{int64(1)},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func testRule(t *testing.T, filename string, rule lint.Rule, config ...*lint.RuleConfig) {
|
func testRule(t *testing.T, filename string, rule lint.Rule, config ...*lint.RuleConfig) {
|
||||||
baseDir := "../fixtures/"
|
baseDir := "../fixtures/"
|
||||||
filename = filename + ".go"
|
filename = filename + ".go"
|
||||||
@ -82,17 +59,14 @@ func testRule(t *testing.T, filename string, rule lint.Rule, config ...*lint.Rul
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Cannot get file info for %s: %v", rule.Name(), err)
|
t.Fatalf("Cannot get file info for %s: %v", rule.Name(), err)
|
||||||
}
|
}
|
||||||
ins := parseInstructions(t, filename, src)
|
|
||||||
if ins == nil {
|
|
||||||
t.Errorf("Test file %v does not have instructions", filename)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if config == nil {
|
|
||||||
assertFailures(t, baseDir, stat, src, []lint.Rule{rule}, map[string]lint.RuleConfig{})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c := map[string]lint.RuleConfig{}
|
c := map[string]lint.RuleConfig{}
|
||||||
|
if config != nil {
|
||||||
c[rule.Name()] = *config[0]
|
c[rule.Name()] = *config[0]
|
||||||
|
}
|
||||||
|
if parseInstructions(t, filename, src) == nil {
|
||||||
|
assertSuccess(t, baseDir, stat, src, []lint.Rule{rule}, c)
|
||||||
|
return
|
||||||
|
}
|
||||||
assertFailures(t, baseDir, stat, src, []lint.Rule{rule}, c)
|
assertFailures(t, baseDir, stat, src, []lint.Rule{rule}, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +77,11 @@ func TestAll(t *testing.T) {
|
|||||||
"cyclomatic.go": true,
|
"cyclomatic.go": true,
|
||||||
"cyclomatic-2.go": true,
|
"cyclomatic-2.go": true,
|
||||||
"max-public-structs.go": true,
|
"max-public-structs.go": true,
|
||||||
|
"lint-file-header1.go": true,
|
||||||
|
"lint-file-header2.go": true,
|
||||||
|
"lint-file-header3.go": true,
|
||||||
|
"lint-file-header4.go": true,
|
||||||
|
"lint-file-header5.go": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
rx, err := regexp.Compile(*lintMatch)
|
rx, err := regexp.Compile(*lintMatch)
|
||||||
@ -138,6 +117,28 @@ func TestAll(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func assertSuccess(t *testing.T, baseDir string, fi os.FileInfo, src []byte, rules []lint.Rule, config map[string]lint.RuleConfig) error {
|
||||||
|
l := lint.New(func(file string) ([]byte, error) {
|
||||||
|
return ioutil.ReadFile(baseDir + file)
|
||||||
|
})
|
||||||
|
|
||||||
|
ps, err := l.Lint([]string{fi.Name()}, rules, lint.Config{
|
||||||
|
Rules: config,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
failures := ""
|
||||||
|
for p := range ps {
|
||||||
|
failures += p.Failure
|
||||||
|
}
|
||||||
|
if failures != "" {
|
||||||
|
t.Errorf("Expected the rule to pass but got the following failures: %s", failures)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func assertFailures(t *testing.T, baseDir string, fi os.FileInfo, src []byte, rules []lint.Rule, config map[string]lint.RuleConfig) error {
|
func assertFailures(t *testing.T, baseDir string, fi os.FileInfo, src []byte, rules []lint.Rule, config map[string]lint.RuleConfig) error {
|
||||||
l := lint.New(func(file string) ([]byte, error) {
|
l := lint.New(func(file string) ([]byte, error) {
|
||||||
return ioutil.ReadFile(baseDir + file)
|
return ioutil.ReadFile(baseDir + file)
|
14
test/max-public-structs_test.go
Normal file
14
test/max-public-structs_test.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mgechev/revive/lint"
|
||||||
|
"github.com/mgechev/revive/rule"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMaxPublicStructs(t *testing.T) {
|
||||||
|
testRule(t, "max-public-structs", &rule.MaxPublicStructsRule{}, &lint.RuleConfig{
|
||||||
|
Arguments: []interface{}{int64(1)},
|
||||||
|
})
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user