Skip to content
Open
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
11 changes: 6 additions & 5 deletions rules/aip0231/request_names_field.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ package aip0231

import (
"fmt"
"strings"

"github.com/gertd/go-pluralize"
"github.com/googleapis/api-linter/v2/lint"
"github.com/googleapis/api-linter/v2/locations"
"github.com/googleapis/api-linter/v2/rules/internal/utils"
"google.golang.org/protobuf/reflect/protoreflect"
)

Expand Down Expand Up @@ -78,10 +79,10 @@ var namesField = &lint.MessageRule{
}

// Rule check: Ensure that the standard get request message field is the
// correct type. Note: Use m.Name()[8:len(m.Name())-7]) to retrieve
// the resource name from the batch get request, for example:
// "BatchGetBooksRequest" -> "Books"
rightTypeName := fmt.Sprintf("Get%sRequest", pluralize.NewClient().Singular(string(m.Name())[8:len(m.Name())-7]))
// correct type. Note: Retrieve the resource name from the batch get
// request, for example: "BatchGetBooksRequest" -> "Books"
pluralName := strings.TrimPrefix(strings.TrimSuffix(string(m.Name()), "Request"), "BatchGet")
rightTypeName := fmt.Sprintf("Get%sRequest", utils.ResourceSingular(pluralName, m))
if getReqMsg != nil && (getReqMsg.Message() == nil || getReqMsg.Message().Name() != protoreflect.Name(rightTypeName)) {
problems = append(problems, lint.Problem{
Message: fmt.Sprintf(`The "requests" field on Batch Get Request should be a %q type`, rightTypeName),
Expand Down
69 changes: 69 additions & 0 deletions rules/aip0231/request_names_field_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,72 @@ func TestNamesField(t *testing.T) {
})
}
}

func TestNamesFieldResourceAnnotation(t *testing.T) {
tests := []struct {
testName string
src string
problems testutils.Problems
problemDesc func(m protoreflect.MessageDescriptor) protoreflect.Descriptor
}{
{
testName: "Valid-ResourceSingularMetadata",
src: `
import "google/api/resource.proto";

message BatchGetImpressionMetadataRequest {
repeated GetImpressionMetadataRequest requests = 1;
}
message GetImpressionMetadataRequest {}
message ImpressionMetadata {
option (google.api.resource) = {
type: "example.com/ImpressionMetadata"
pattern: "dataProviders/{dp}/impressionMetadata/{im}"
singular: "impressionMetadata"
plural: "impressionMetadata"
};
}
`,
problems: testutils.Problems{},
},
{
testName: "Invalid-WrongTypeWithResourceSingular",
src: `
import "google/api/resource.proto";

message BatchGetImpressionMetadataRequest {
repeated string requests = 1;
}
message ImpressionMetadata {
option (google.api.resource) = {
type: "example.com/ImpressionMetadata"
pattern: "dataProviders/{dp}/impressionMetadata/{im}"
singular: "impressionMetadata"
plural: "impressionMetadata"
};
}
`,
problems: testutils.Problems{{Message: `The "requests" field on Batch Get Request should be a "GetImpressionMetadataRequest" type`}},
problemDesc: func(m protoreflect.MessageDescriptor) protoreflect.Descriptor {
return m.Fields().ByName("requests")
},
},
}

for _, test := range tests {
t.Run(test.testName, func(t *testing.T) {
file := testutils.ParseProto3String(t, test.src)
m := file.Messages().Get(0)

var problemDesc protoreflect.Descriptor = m
if test.problemDesc != nil {
problemDesc = test.problemDesc(m)
}

problems := namesField.Lint(file)
if diff := test.problems.SetDescriptor(problemDesc).Diff(problems); diff != "" {
t.Error(diff)
}
})
}
}
6 changes: 3 additions & 3 deletions rules/aip0231/response_resource_field.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import (
"fmt"
"strings"

"github.com/gertd/go-pluralize"
"github.com/googleapis/api-linter/v2/lint"
"github.com/googleapis/api-linter/v2/rules/internal/utils"
"google.golang.org/protobuf/reflect/protoreflect"
)

Expand All @@ -29,8 +29,8 @@ var resourceField = &lint.MessageRule{
OnlyIf: isBatchGetResponseMessage,
LintMessage: func(m protoreflect.MessageDescriptor) []lint.Problem {
// The singular form the resource message name; the first letter capitalized.
plural := strings.TrimSuffix(strings.TrimPrefix(string(m.Name()), "BatchGet"), "Response")
resourceMsgName := pluralize.NewClient().Singular(plural)
pluralName := strings.TrimPrefix(strings.TrimSuffix(string(m.Name()), "Response"), "BatchGet")
resourceMsgName := utils.ResourceSingular(pluralName, m)

for i := 0; i < m.Fields().Len(); i++ {
fieldDesc := m.Fields().Get(i)
Expand Down
55 changes: 55 additions & 0 deletions rules/aip0231/response_resource_field_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,58 @@ func TestResourceField(t *testing.T) {
})
}
}

func TestResourceFieldResourceAnnotation(t *testing.T) {
tests := []struct {
testName string
Field string
problems testutils.Problems
problemDesc func(m protoreflect.MessageDescriptor) protoreflect.Descriptor
}{
{
testName: "Valid-ResourceSingularMetadata",
Field: "repeated ImpressionMetadata impression_metadata",
problems: testutils.Problems{},
},
{
testName: "MissingField-ResourceSingularMetadata",
Field: "string response",
problems: testutils.Problems{{Message: `no "ImpressionMetadata" type field`}},
problemDesc: func(m protoreflect.MessageDescriptor) protoreflect.Descriptor {
return m
},
},
}

for _, test := range tests {
t.Run(test.testName, func(t *testing.T) {
file := testutils.ParseProto3Tmpl(t, `
import "google/api/resource.proto";

message BatchGetImpressionMetadataResponse {
{{.Field}} = 1;
}
message ImpressionMetadata {
option (google.api.resource) = {
type: "example.com/ImpressionMetadata"
pattern: "dataProviders/{dp}/impressionMetadata/{im}"
singular: "impressionMetadata"
plural: "impressionMetadata"
};
}
`, test)

m := file.Messages().Get(0)

var problemDesc protoreflect.Descriptor = m.Fields().Get(0)
if test.problemDesc != nil {
problemDesc = test.problemDesc(m)
}

problems := resourceField.Lint(file)
if diff := test.problems.SetDescriptor(problemDesc).Diff(problems); diff != "" {
t.Error(diff)
}
})
}
}
6 changes: 3 additions & 3 deletions rules/aip0233/request_requests_field.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import (
"fmt"
"strings"

"github.com/gertd/go-pluralize"
"github.com/googleapis/api-linter/v2/lint"
"github.com/googleapis/api-linter/v2/locations"
"github.com/googleapis/api-linter/v2/rules/internal/utils"
"google.golang.org/protobuf/reflect/protoreflect"
)

Expand Down Expand Up @@ -52,8 +52,8 @@ var requestRequestsField = &lint.MessageRule{
// Rule check: Ensure that the standard create request message field is the
// correct type. Note: Retrieve the resource name from the the batch create
// request, for example: "BatchCreateBooksRequest" -> "Books"
rightTypeName := fmt.Sprintf("Create%sRequest",
pluralize.NewClient().Singular(strings.TrimPrefix(strings.TrimSuffix(string(m.Name()), "Request"), "BatchCreate")))
pluralName := strings.TrimPrefix(strings.TrimSuffix(string(m.Name()), "Request"), "BatchCreate")
rightTypeName := fmt.Sprintf("Create%sRequest", utils.ResourceSingular(pluralName, m))
if requests.Message() == nil || requests.Message().Name() != protoreflect.Name(rightTypeName) {
problems = append(problems, lint.Problem{
Message: fmt.Sprintf(`The "requests" field on Batch Create Request should be a %q type`, rightTypeName),
Expand Down
58 changes: 58 additions & 0 deletions rules/aip0233/request_requests_field_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,61 @@ func TestRequestRequestsField(t *testing.T) {
})
}
}

func TestRequestRequestsFieldResourceAnnotation(t *testing.T) {
tests := []struct {
testName string
Field string
problems testutils.Problems
problemDesc func(m protoreflect.MessageDescriptor) protoreflect.Descriptor
}{
{
testName: "Valid-ResourceSingularMetadata",
Field: "repeated CreateImpressionMetadataRequest requests = 1;",
problems: testutils.Problems{},
},
{
testName: "Invalid-WrongTypeWithResourceSingular",
Field: "repeated int32 requests = 1;",
problems: testutils.Problems{{
Suggestion: "CreateImpressionMetadataRequest",
}},
problemDesc: func(m protoreflect.MessageDescriptor) protoreflect.Descriptor {
return m.Fields().ByName("requests")
},
},
}

for _, test := range tests {
t.Run(test.testName, func(t *testing.T) {
file := testutils.ParseProto3Tmpl(t, `
import "google/api/resource.proto";

message BatchCreateImpressionMetadataRequest {
{{.Field}}
}
message CreateImpressionMetadataRequest {}
message ImpressionMetadata {
option (google.api.resource) = {
type: "example.com/ImpressionMetadata"
pattern: "dataProviders/{dp}/impressionMetadata/{im}"
singular: "impressionMetadata"
plural: "impressionMetadata"
};
}
`, test)

m := file.Messages().Get(0)

var problemDesc protoreflect.Descriptor = m
if test.problemDesc != nil {
problemDesc = test.problemDesc(m)
}

problems := requestRequestsField.Lint(file)
if diff := test.problems.SetDescriptor(problemDesc).Diff(problems); diff != "" {
t.Error(diff)
}
})
}
}
5 changes: 3 additions & 2 deletions rules/aip0233/response_resource_field.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import (
"fmt"
"strings"

"github.com/gertd/go-pluralize"
"github.com/googleapis/api-linter/v2/lint"
"github.com/googleapis/api-linter/v2/rules/internal/utils"
"google.golang.org/protobuf/reflect/protoreflect"
)

Expand All @@ -31,7 +31,8 @@ var responseResourceField = &lint.MessageRule{
// the singular form the resource name, the first letter is Capitalized.
// Note: Retrieve the resource name from the the batch create response,
// for example: "BatchCreateBooksResponse" -> "Books"
resourceMsgName := pluralize.NewClient().Singular(strings.TrimPrefix(strings.TrimSuffix(string(m.Name()), "Response"), "BatchCreate"))
pluralName := strings.TrimPrefix(strings.TrimSuffix(string(m.Name()), "Response"), "BatchCreate")
resourceMsgName := utils.ResourceSingular(pluralName, m)

for i := 0; i < m.Fields().Len(); i++ {
fieldDesc := m.Fields().Get(i)
Expand Down
55 changes: 55 additions & 0 deletions rules/aip0233/response_resource_field_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,58 @@ func TestResponseResourceField(t *testing.T) {
})
}
}

func TestResponseResourceFieldResourceAnnotation(t *testing.T) {
tests := []struct {
testName string
Src string
problems testutils.Problems
problemDesc func(m protoreflect.MessageDescriptor) protoreflect.Descriptor
}{
{
testName: "Valid-ResourceSingularMetadata",
Src: `repeated ImpressionMetadata impression_metadata = 1;`,
problems: testutils.Problems{},
},
{
testName: "MissingField-ResourceSingularMetadata",
Src: `string response = 1;`,
problems: testutils.Problems{{Message: `no "ImpressionMetadata" type field`}},
problemDesc: func(m protoreflect.MessageDescriptor) protoreflect.Descriptor {
return m
},
},
}

for _, test := range tests {
t.Run(test.testName, func(t *testing.T) {
file := testutils.ParseProto3Tmpl(t, `
import "google/api/resource.proto";

message BatchCreateImpressionMetadataResponse {
{{.Src}}
}
message ImpressionMetadata {
option (google.api.resource) = {
type: "example.com/ImpressionMetadata"
pattern: "dataProviders/{dp}/impressionMetadata/{im}"
singular: "impressionMetadata"
plural: "impressionMetadata"
};
}
`, test)

m := file.Messages().Get(0)

var problemDesc protoreflect.Descriptor = m.Fields().Get(0)
if test.problemDesc != nil {
problemDesc = test.problemDesc(m)
}

problems := responseResourceField.Lint(file)
if diff := test.problems.SetDescriptor(problemDesc).Diff(problems); diff != "" {
t.Error(diff)
}
})
}
}
6 changes: 3 additions & 3 deletions rules/aip0234/request_requests_field.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import (
"fmt"
"strings"

"github.com/gertd/go-pluralize"
"github.com/googleapis/api-linter/v2/lint"
"github.com/googleapis/api-linter/v2/locations"
"github.com/googleapis/api-linter/v2/rules/internal/utils"
"google.golang.org/protobuf/reflect/protoreflect"
)

Expand Down Expand Up @@ -52,8 +52,8 @@ var requestRequestsField = &lint.MessageRule{
// Rule check: Ensure that the standard update request message field is the
// correct type. Note: Retrieve the resource name from the the batch update
// request, for example: "BatchUpdateBooksRequest" -> "Books"
rightTypeName := fmt.Sprintf("Update%sRequest",
pluralize.NewClient().Singular(strings.TrimPrefix(strings.TrimSuffix(string(m.Name()), "Request"), "BatchUpdate")))
pluralName := strings.TrimPrefix(strings.TrimSuffix(string(m.Name()), "Request"), "BatchUpdate")
rightTypeName := fmt.Sprintf("Update%sRequest", utils.ResourceSingular(pluralName, m))
if requests.Message() == nil || requests.Message().Name() != protoreflect.Name(rightTypeName) {
problems = append(problems, lint.Problem{
Message: fmt.Sprintf(`The "requests" field on Batch Update Request should be a %q type`, rightTypeName),
Expand Down
Loading