Repository: googleapis/api-linter (go)

Issue:
check if java_outer_classname is set to proto filename
According to [AIP191](https://aip.dev/191):

> The java_outer_classname annotation must be set, and should be set to the name of the proto filename, in PascalCase, with Proto appended. Example: LibraryProto.

Right now, the implemented rule only checks if java_outer_classname is set. In case it is, it does not check if it set to the filename as is recommended by the AIP191.

I think we could include this checking. 

Pull request:
[AIP-191] Enforce java_outer_classname.
Fixes #535.

Patch:
diff --git a/rules/aip0191/java_outer_classname.go b/rules/aip0191/java_outer_classname.go
index 549cd9d..848e54f 100644
--- a/rules/aip0191/java_outer_classname.go
+++ b/rules/aip0191/java_outer_classname.go
@@ -31,9 +31,12 @@ var javaOuterClassname = &lint.FileRule{
 		return hasPackage(f) && !strings.HasSuffix(f.GetPackage(), ".master")
 	},
 	LintFile: func(f *desc.FileDescriptor) []lint.Problem {
-		if f.GetFileOptions().GetJavaOuterClassname() == "" {
-			filename := filepath.Base(f.GetName())
-			want := strcase.UpperCamelCase(strings.ReplaceAll(filename, ".", "_"))
+		filename := filepath.Base(f.GetName())
+		want := strcase.UpperCamelCase(strings.ReplaceAll(filename, ".", "_"))
+
+		// We ignore case on the comparisons to not be too pedantic on compound
+		// word protos without underscores in the filename.
+		if !strings.EqualFold(f.GetFileOptions().GetJavaOuterClassname(), strings.ToUpper(want)) {
 			return []lint.Problem{{
 				Message: fmt.Sprintf(
 					"Proto files should set `option java_outer_classname = %q`.",


Test patch:
diff --git a/rules/aip0191/java_outer_classname_test.go b/rules/aip0191/java_outer_classname_test.go
index 9bdcf73..f10ae3a 100644
--- a/rules/aip0191/java_outer_classname_test.go
+++ b/rules/aip0191/java_outer_classname_test.go
@@ -30,13 +30,19 @@ func TestJavaOuterClassname(t *testing.T) {
 	}{
 		{"Valid", "test.proto", []string{"package foo.v1;", `option java_outer_classname = "TestProto";`}, testutils.Problems{}},
 		{"ValidWithPath", "foo/bar/test.proto", []string{"package foo.v1;", `option java_outer_classname = "TestProto";`}, testutils.Problems{}},
-		{"Invalid", "test.proto", []string{"package foo.v1;", ""}, testutils.Problems{{Message: `java_outer_classname = "TestProto"`}}},
-		{"InvalidWithPath", "foo/bar/test.proto", []string{"package foo.v1;"}, testutils.Problems{{Message: `java_outer_classname = "TestProto"`}}},
+		{"ValidCompound", "appleorange.proto", []string{"package foo.v1;", `option java_outer_classname = "AppleOrangeProto";`}, testutils.Problems{}},
+		{"ValidCompoundWithUnderscore", "apple_orange.proto", []string{"package foo.v1;", `option java_outer_classname = "AppleOrangeProto";`}, testutils.Problems{}},
+		{"ValidCompoundWithPath", "foo/bar/appleorange.proto", []string{"package foo.v1;", `option java_outer_classname = "AppleOrangeProto";`}, testutils.Problems{}},
+		{"InvalidWrong", "test.proto", []string{"package foo.v1;", `option java_outer_classname = "OtherProto";`}, testutils.Problems{{Message: `java_outer_classname = "TestProto"`}}},
+		{"InvalidWrongWithPath", "foo/bar/test.proto", []string{"package foo.v1;", `option java_outer_classname = "OtherProto";`}, testutils.Problems{{Message: `java_outer_classname = "TestProto"`}}},
+		{"InvalidMissing", "test.proto", []string{"package foo.v1;", ""}, testutils.Problems{{Message: `java_outer_classname = "TestProto"`}}},
+		{"InvalidMissingWithPath", "foo/bar/test.proto", []string{"package foo.v1;"}, testutils.Problems{{Message: `java_outer_classname = "TestProto"`}}},
 		{"Ignored", "test.proto", []string{"", ""}, testutils.Problems{}},
 		{"IgnoredMaster", "test.proto", []string{"package foo.master;", ""}, testutils.Problems{}},
 	} {
 		t.Run(test.name, func(t *testing.T) {
-			f := testutils.ParseProto3String(t, strings.Join(test.statements, "\n"))
+			files := testutils.ParseProtoStrings(t, map[string]string{test.filename: strings.Join(test.statements, "\n")})
+			f := files[test.filename]
 			if diff := test.problems.SetDescriptor(f).Diff(javaOuterClassname.Lint(f)); diff != "" {
 				t.Errorf(diff)
 			}