Skip to content

Commit

Permalink
add test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
jhump committed Apr 3, 2024
1 parent 042d689 commit 0569d90
Show file tree
Hide file tree
Showing 2 changed files with 325 additions and 4 deletions.
325 changes: 323 additions & 2 deletions linker/linker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ func TestLinkerValidation(t *testing.T) {
expectedErr: `foo.proto:1:8: cycle found in imports: "foo.proto" -> "foo2.proto" -> "foo.proto"` +
` || foo2.proto:1:8: cycle found in imports: "foo2.proto" -> "foo.proto" -> "foo2.proto"`,
},
"failure_import_lite_from_nonlite": {
input: map[string]string{
"foo.proto": `option optimize_for=LITE_RUNTIME;`,
"foo2.proto": `import "foo.proto"; message baz{}`,
},
// since files are compiled concurrently, there are two possible outcomes
expectedErr: `foo2.proto:1:8: a file that does not use optimize_for=LITE_RUNTIME may not import file "foo.proto" that does`,
},
"failure_enum_cpp_scope": {
input: map[string]string{
"foo.proto": "enum foo { bar = 1; baz = 2; } enum fu { bar = 1; baz = 2; }",
Expand Down Expand Up @@ -290,6 +298,12 @@ func TestLinkerValidation(t *testing.T) {
},
expectedErr: "foo.proto:1:66: field fu.baz.foobar.a: option default: expecting string, got double",
},
"failure_editions_default_with_implicit_presence": {
input: map[string]string{
"foo.proto": `edition = "2023"; message Foo { string s = 1 [default="abc", features.field_presence=IMPLICIT]; }`,
},
expectedErr: "foo.proto:1:47: default value is not allowed on fields with implicit presence",
},
"failure_enum_default_not_found": {
input: map[string]string{
"foo.proto": "package fu.baz; enum abc { OK=0; NOK=1; } message foobar{ optional abc a = 1 [default = NACK]; }",
Expand Down Expand Up @@ -2204,6 +2218,18 @@ func TestLinkerValidation(t *testing.T) {
},
expectedErr: `test.proto:3:3: packed option is only allowed on repeated fields`,
},
"failure_editions_packed_option_not_allowed": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
message A {
repeated uint32 ids = 1 [packed=true];
}
`,
},
expectedErr: `test.proto:4:34: field foo.A.ids: packed option is not allowed in editions; use option features.repeated_field_encoding instead`,
},
"failure_editions_feature_on_wrong_target_type": {
input: map[string]string{
"test.proto": `
Expand Down Expand Up @@ -2329,7 +2355,7 @@ func TestLinkerValidation(t *testing.T) {
}
`,
},
expectedErr: `test.proto:4:30: extension range cannot have declarations and have verification of UNVERIFIED`,
expectedErr: `test.proto:4:17: extension range cannot have declarations and have verification of UNVERIFIED`,
},
"failure_extension_declaration_without_number": {
input: map[string]string{
Expand Down Expand Up @@ -2811,7 +2837,302 @@ func TestLinkerValidation(t *testing.T) {
}
`,
},
expectedErr: `test.proto:14:31: expected extension with number 3 to be declared in type foo.A, but no declaration found at test.proto:5:30`,
expectedErr: `test.proto:14:31: expected extension with number 3 to be declared in type foo.A, but no declaration found at test.proto:5:17`,
},
"success_field_presence": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
option features.field_presence = IMPLICIT;
message A {
B b = 1 [features.field_presence = LEGACY_REQUIRED];
message B {
string s = 1 [features.field_presence = EXPLICIT];
}
A a = 2 [features.field_presence = EXPLICIT];
uint64 u = 3 [features.field_presence = IMPLICIT];
}
`,
},
},
"failure_field_presence_on_oneof_field": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
message A {
oneof b {
string s = 1 [features.field_presence = EXPLICIT];
int64 n = 2;
}
}
`,
},
expectedErr: `test.proto:5:40: oneof fields may not specify field presence`,
},
"failure_field_presence_on_repeated_field": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
message A {
repeated string s = 1 [features.field_presence = IMPLICIT];
}
`,
},
expectedErr: `test.proto:4:41: repeated fields may not specify field presence`,
},
"failure_field_presence_on_map_field": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
message A {
map<string,string> s = 1 [features.field_presence = IMPLICIT];
}
`,
},
expectedErr: `test.proto:4:44: repeated fields may not specify field presence`,
},
"failure_field_presence_on_message_field": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
message A {
A a = 1 [features.field_presence = IMPLICIT];
}
`,
},
expectedErr: `test.proto:4:27: message fields may not specify implicit presence`,
},
"failure_field_presence_on_extension_field": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
message A {
extensions 1 to 100;
}
extend A {
string s = 1 [features = {
field_presence:LEGACY_REQUIRED
}];
}
`,
},
expectedErr: `test.proto:8:17: extension fields may not specify field presence`,
},
"failure_field_presence_on_file": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
option features={
field_presence : LEGACY_REQUIRED;
};
message A {
string s = 1;
}
`,
},
expectedErr: `test.proto:4:9: LEGACY_REQUIRED field presence cannot be set as the default for a file`,
},
"success_repeated_field_encoding": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
option features.repeated_field_encoding=EXPANDED;
message A {
repeated string s = 1 [features.repeated_field_encoding=EXPANDED];
map<string,string> m = 2 [features.repeated_field_encoding=EXPANDED];
repeated A a = 3 [features.repeated_field_encoding=EXPANDED];
repeated bool b = 4 [features.repeated_field_encoding=PACKED];
repeated double d = 5 [features.repeated_field_encoding=PACKED];
repeated E e = 6 [features.repeated_field_encoding=PACKED];
enum E { ZERO=0; }
}
`,
},
},
"failure_repeated_field_encoding_not_repeated": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
message A {
string s = 1 [features.repeated_field_encoding=EXPANDED];
}
`,
},
expectedErr: `test.proto:4:32: only repeated fields may specify repeated field encoding`,
},
"failure_repeated_field_encoding_not_packable": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
message A {
repeated string s = 1 [features.repeated_field_encoding=PACKED];
}
`,
},
expectedErr: `test.proto:4:41: only repeated primitive fields may specify packed encoding`,
},
"failure_repeated_field_encoding_not_packable_map": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
message A {
map<string,string> s = 1 [features.repeated_field_encoding=PACKED];
}
`,
},
expectedErr: `test.proto:4:44: only repeated primitive fields may specify packed encoding`,
},
"success_utf8_validation": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
option features = {
utf8_validation:NONE;
};
message A {
string s = 1 [features.utf8_validation=VERIFY];
map<string,A> ma = 2 [features.utf8_validation=VERIFY];
map<uint32,string> mu = 3 [features.utf8_validation=VERIFY];
map<string,string> ms = 4 [features.utf8_validation=VERIFY];
}
`,
},
},
"failure_utf8_validation_not_string": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
message A {
bytes s = 1 [features.utf8_validation=VERIFY];
}
`,
},
expectedErr: `test.proto:4:31: only string fields may specify UTF8 validation`,
},
"failure_utf8_validation_not_string_map": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
message A {
map<uint32,bytes> m = 1 [features.utf8_validation=VERIFY];
}
`,
},
expectedErr: `test.proto:4:43: only string fields may specify UTF8 validation`,
},
"failure_utf8_validation_java_option": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
option java_string_check_utf8 = true;
message A {
map<uint32,bytes> m = 1;
}
`,
},
expectedErr: `test.proto:3:8: file option java_string_check_utf8 is not allowed with editions; import "google/protobuf/java_features.proto" and use (pb.java).utf8_validation instead`,
},
"success_message_encoding": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
option features.message_encoding = DELIMITED;
message A {
A a = 1 [features={
message_encoding : LENGTH_PREFIXED,
}];
repeated A as = 2 [features.message_encoding=DELIMITED];
}
`,
},
},
"failure_message_encoding_not_message": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
message A {
repeated string s = 1 [features={
message_encoding : LENGTH_PREFIXED,
}];
}
`,
},
expectedErr: `test.proto:5:17: only message fields may specify message encoding`,
},
"failure_message_encoding_map": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
message A {
map<string,string> m = 1 [features={
message_encoding : LENGTH_PREFIXED,
}];
}
`,
},
expectedErr: `test.proto:5:17: only message fields may specify message encoding`,
},
"success_editions_ctype": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
message A {
string s = 1 [ctype=CORD];
bytes b = 2 [ctype=STRING_PIECE];
repeated string r = 3 [ctype=STRING];
extensions 10 to 100;
}
extend A {
string ext = 10 [ctype=STRING_PIECE];
}
`,
},
},
"failure_editions_ctype_not_string_or_bytes": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
message A {
uint32 s = 1 [ctype=STRING_PIECE];
}
`,
},
expectedErr: `test.proto:4:23: ctype option can only be used on string and bytes fields`,
},
"failure_editions_ctype_ext_cannot_be_cord": {
input: map[string]string{
"test.proto": `
edition = "2023";
package foo;
message A {
extensions 10 to 100;
}
extend A {
string ext = 10 [ctype=CORD];
}
`,
},
expectedErr: `test.proto:7:26: ctype option cannot be CORD for extension fields`,
},
}

Expand Down
4 changes: 2 additions & 2 deletions linker/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func (r *result) validateFile(handler *reporter.Handler) error {
}
if opts != nil && opts.JavaStringCheckUtf8 != nil {
span := r.findOptionSpan(r, internal.FileOptionsJavaStringCheckUTF8Tag)
err := handler.HandleErrorf(span, `file option java_string_check_utf8 is not allowed with editions; import "google/protobuf/java_features.proto" and use the (pb.java).utf8_validation instead`)
err := handler.HandleErrorf(span, `file option java_string_check_utf8 is not allowed with editions; import "google/protobuf/java_features.proto" and use (pb.java).utf8_validation instead`)
if err != nil {
return err
}
Expand Down Expand Up @@ -917,7 +917,7 @@ func findOptionSpan(
// Either an exact match (if equal) or this option points *inside* the
// item we care about (if greater). Either way, the first such result
// is a keeper.
bestMatch = n.Val
bestMatch = n.Name.Parts[len(path)-1]
bestMatchLen = len(n.Name.Parts)
return false
}
Expand Down

0 comments on commit 0569d90

Please sign in to comment.