Skip to content

Commit

Permalink
Merge pull request #24 from jpreese/service-names-end-with
Browse files Browse the repository at this point in the history
Implement SERVICE_NAMES_END_WITH rule
  • Loading branch information
yoheimuta authored Jun 12, 2019
2 parents 30f8cdf + 96c145f commit 18c012b
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ The rule set follows:
| SERVICE_NAMES_UPPER_CAMEL_CASE | Verifies that all service names are CamelCase (with an initial capital). |
| MAX_LINE_LENGTH | Enforces a maximum line length. |
| INDENT | Enforces a consistent indentation style. |
| SERVICE_NAMES_END_WITH | Enforces a consistent suffix for service names. |

`-` is a bad style, `+` is a good style:

Expand Down
54 changes: 54 additions & 0 deletions internal/addon/rules/serviceNamesEndWithRule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package rules

import (
"strings"

"github.com/yoheimuta/go-protoparser/parser"
"github.com/yoheimuta/protolint/internal/addon/rules/internal/visitor"
"github.com/yoheimuta/protolint/internal/linter/report"
)

// ServiceNamesEndWithRule verifies that all service names end with the specified value.
type ServiceNamesEndWithRule struct {
text string
}

// NewServiceNamesEndWithRule creates a new ServiceNamesEndWithRule.
func NewServiceNamesEndWithRule(text string) ServiceNamesEndWithRule {
return ServiceNamesEndWithRule{
text: text,
}
}

// ID returns the ID of this rule.
func (r ServiceNamesEndWithRule) ID() string {
return "SERVICE_NAMES_END_WITH"
}

// Purpose returns the purpose of this rule.
func (r ServiceNamesEndWithRule) Purpose() string {
return "Verifies that all service names end with the specified value."
}

// Apply applies the rule to the proto.
func (r ServiceNamesEndWithRule) Apply(proto *parser.Proto) ([]report.Failure, error) {
v := &serviceNamesEndWithVisitor{
BaseAddVisitor: visitor.NewBaseAddVisitor(),
text: r.text,
}

return visitor.RunVisitor(v, proto, r.ID())
}

type serviceNamesEndWithVisitor struct {
*visitor.BaseAddVisitor
text string
}

// VisitService checks the service.
func (v *serviceNamesEndWithVisitor) VisitService(service *parser.Service) bool {
if !strings.HasSuffix(service.ServiceName, v.text) {
v.AddFailuref(service.Meta.Pos, "Service name %q must end with %s", service.ServiceName, v.text)
}
return false
}
78 changes: 78 additions & 0 deletions internal/addon/rules/serviceNamesEndWithRule_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package rules_test

import (
"reflect"
"testing"

"github.com/yoheimuta/go-protoparser/parser"
"github.com/yoheimuta/go-protoparser/parser/meta"
"github.com/yoheimuta/protolint/internal/addon/rules"
"github.com/yoheimuta/protolint/internal/linter/report"
)

func TestValidServiceNamesEndWithRule_Apply(t *testing.T) {
validTestCase := struct {
name string
inputProto *parser.Proto
wantFailures []report.Failure
}{
name: "no failures for proto with valid service names",
inputProto: &parser.Proto{
ProtoBody: []parser.Visitee{
&parser.Service{
ServiceName: "SomeServiceService",
},
&parser.Service{
ServiceName: "AnotherService",
},
},
},
}

t.Run(validTestCase.name, func(t *testing.T) {
rule := rules.NewServiceNamesEndWithRule("Service")

_, err := rule.Apply(validTestCase.inputProto)
if err != nil {
t.Errorf("got err %v, but want nil", err)
return
}
})
}

func TestInvalidServiceNamesEndWithRule_Apply(t *testing.T) {
invalidTestCase := struct {
name string
inputProto *parser.Proto
wantFailures []report.Failure
}{
name: "failures for proto with invalid service names",
inputProto: &parser.Proto{
ProtoBody: []parser.Visitee{
&parser.Service{
ServiceName: "SomeThing",
},
&parser.Service{
ServiceName: "AnotherThing",
},
},
},
wantFailures: []report.Failure{
report.Failuref(meta.Position{}, `Service name "SomeThing" must end with Service`),
report.Failuref(meta.Position{}, `Service name "AnotherThing" must end with Service`),
},
}

t.Run(invalidTestCase.name, func(t *testing.T) {
rule := rules.NewServiceNamesEndWithRule("Service")

got, err := rule.Apply(invalidTestCase.inputProto)
if err != nil {
t.Errorf("got err %v, but want nil", err)
return
}
if !reflect.DeepEqual(got, invalidTestCase.wantFailures) {
t.Errorf("got %v, but want %v", got, invalidTestCase.wantFailures)
}
})
}
4 changes: 4 additions & 0 deletions internal/cmd/subcmds/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ func defaultRules(
) []rule.Rule {
maxLineLength := option.MaxLineLength
indent := option.Indent
serviceNamesEndWith := option.ServiceNamesEndWith

return []rule.Rule{
rules.NewEnumFieldNamesUpperSnakeCaseRule(),
Expand All @@ -29,6 +30,9 @@ func defaultRules(
indent.Newline,
fixMode,
),
rules.NewServiceNamesEndWithRule(
serviceNamesEndWith.Text,
),
}
}

Expand Down
5 changes: 3 additions & 2 deletions internal/linter/config/rulesOption.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package config

// RulesOption represents the option for some rules.
type RulesOption struct {
MaxLineLength MaxLineLengthOption `yaml:"max_line_length"`
Indent IndentOption `yaml:"indent"`
MaxLineLength MaxLineLengthOption `yaml:"max_line_length"`
Indent IndentOption `yaml:"indent"`
ServiceNamesEndWith ServiceNamesEndWithOption `yaml:"service_names_end_with"`
}
6 changes: 6 additions & 0 deletions internal/linter/config/serviceNamesEndWithOption.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package config

// ServiceNamesEndWithOption represents the option for the SERVICE_NAMES_END_WITH rule.
type ServiceNamesEndWithOption struct {
Text string `yaml:"text"`
}

0 comments on commit 18c012b

Please sign in to comment.