reflect/protodesc: add validation for NewFile
This covers most of the TODO around validation. I left open the ones
that we didn't have clear consensus on yet.
Change-Id: I336c53173ee8d7447558b1e3a0c1ef945e986cd5
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/175140
Reviewed-by: Joe Tsai <joetsai@google.com>
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/reflect/protodesc/protodesc_test.go b/reflect/protodesc/protodesc_test.go
new file mode 100644
index 0000000..b82078e
--- /dev/null
+++ b/reflect/protodesc/protodesc_test.go
@@ -0,0 +1,575 @@
+package protodesc
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/golang/protobuf/v2/internal/scalar"
+ "github.com/golang/protobuf/v2/reflect/protoregistry"
+
+ descriptorpb "github.com/golang/protobuf/v2/types/descriptor"
+)
+
+// Tests validation logic for malformed descriptors.
+func TestNewFile_ValidationErrors(t *testing.T) {
+ testCases := []struct {
+ name string
+ deps []*descriptorpb.FileDescriptorProto
+ fd *descriptorpb.FileDescriptorProto
+ wantErr string
+ }{{
+ name: "field number reserved",
+ fd: &descriptorpb.FileDescriptorProto{
+ Name: scalar.String("field-number-reserved.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("BadMessage"),
+ ReservedRange: []*descriptorpb.DescriptorProto_ReservedRange{{
+ Start: scalar.Int32(3),
+ End: scalar.Int32(4),
+ }},
+ Field: []*descriptorpb.FieldDescriptorProto{{
+ Name: scalar.String("good_field"),
+ Number: scalar.Int32(1),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
+ }, {
+ Name: scalar.String("bad_field"),
+ Number: scalar.Int32(3),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
+ }},
+ }},
+ },
+ wantErr: "reserved number 3",
+ }, {
+ name: "field name reserved",
+ fd: &descriptorpb.FileDescriptorProto{
+ Name: scalar.String("field-name-reserved.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("BadMessage"),
+ ReservedName: []string{"bad_field", "baz"},
+ Field: []*descriptorpb.FieldDescriptorProto{{
+ Name: scalar.String("good_field"),
+ Number: scalar.Int32(1),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
+ }, {
+ Name: scalar.String("bad_field"),
+ Number: scalar.Int32(3),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
+ }},
+ }},
+ },
+ wantErr: `reserved name "bad_field"`,
+ }, {
+ name: "normal field with extendee",
+ deps: []*descriptorpb.FileDescriptorProto{{
+ Name: scalar.String("extensible.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("ExtensibleMessage"),
+ ExtensionRange: []*descriptorpb.DescriptorProto_ExtensionRange{{
+ Start: scalar.Int32(1000),
+ End: scalar.Int32(2000),
+ }},
+ }},
+ }},
+ fd: &descriptorpb.FileDescriptorProto{
+ Name: scalar.String("field-with-extendee.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ Dependency: []string{"extensible.proto"},
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("BadMessage"),
+ Field: []*descriptorpb.FieldDescriptorProto{{
+ Name: scalar.String("good_field"),
+ Number: scalar.Int32(1),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
+ }, {
+ Name: scalar.String("bad_field"),
+ Number: scalar.Int32(3),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
+ Extendee: scalar.String(".foo.ExtensibleMessage"),
+ }},
+ }},
+ },
+ wantErr: "may not have extendee",
+ }, {
+ name: "type_name on int32 field",
+ fd: &descriptorpb.FileDescriptorProto{
+ Name: scalar.String("int32-with-type-name.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ EnumType: []*descriptorpb.EnumDescriptorProto{{
+ Name: scalar.String("AnEnum"),
+ Value: []*descriptorpb.EnumValueDescriptorProto{{
+ Name: scalar.String("UNKNOWN"),
+ Number: scalar.Int32(0),
+ }},
+ }},
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("BadMessage"),
+ Field: []*descriptorpb.FieldDescriptorProto{{
+ Name: scalar.String("good_field"),
+ Number: scalar.Int32(1),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
+ }, {
+ Name: scalar.String("bad_field"),
+ Number: scalar.Int32(3),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
+ TypeName: scalar.String("AnEnum"),
+ }},
+ }},
+ },
+ wantErr: "type_name",
+ }, {
+ name: "type_name on string extension",
+ deps: []*descriptorpb.FileDescriptorProto{{
+ Name: scalar.String("extensible.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("ExtensibleMessage"),
+ ExtensionRange: []*descriptorpb.DescriptorProto_ExtensionRange{{
+ Start: scalar.Int32(1000),
+ End: scalar.Int32(2000),
+ }},
+ }},
+ }},
+ fd: &descriptorpb.FileDescriptorProto{
+ Name: scalar.String("string-ext-with-type-name.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("bar"),
+ Dependency: []string{"extensible.proto"},
+ EnumType: []*descriptorpb.EnumDescriptorProto{{
+ Name: scalar.String("AnEnum"),
+ Value: []*descriptorpb.EnumValueDescriptorProto{{
+ Name: scalar.String("UNKNOWN"),
+ Number: scalar.Int32(0),
+ }},
+ }},
+ Extension: []*descriptorpb.FieldDescriptorProto{{
+ Name: scalar.String("my_ext"),
+ Number: scalar.Int32(1000),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+ Extendee: scalar.String(".foo.ExtensibleMessage"),
+ TypeName: scalar.String("AnEnum"),
+ }},
+ },
+ wantErr: "type_name",
+ }, {
+ name: "oneof_index on extension",
+ deps: []*descriptorpb.FileDescriptorProto{{
+ Name: scalar.String("extensible.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("ExtensibleMessage"),
+ ExtensionRange: []*descriptorpb.DescriptorProto_ExtensionRange{{
+ Start: scalar.Int32(1000),
+ End: scalar.Int32(2000),
+ }},
+ }},
+ }},
+ fd: &descriptorpb.FileDescriptorProto{
+ Name: scalar.String("ext-with-oneof-index.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("bar"),
+ Dependency: []string{"extensible.proto"},
+ Extension: []*descriptorpb.FieldDescriptorProto{{
+ Name: scalar.String("my_ext"),
+ Number: scalar.Int32(1000),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+ Extendee: scalar.String(".foo.ExtensibleMessage"),
+ OneofIndex: scalar.Int32(0),
+ }},
+ },
+ wantErr: "oneof_index",
+ }, {
+ name: "enum with reserved number",
+ fd: &descriptorpb.FileDescriptorProto{
+ Name: scalar.String("enum-with-reserved-number.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ EnumType: []*descriptorpb.EnumDescriptorProto{{
+ Name: scalar.String("AnEnum"),
+ ReservedRange: []*descriptorpb.EnumDescriptorProto_EnumReservedRange{{
+ Start: scalar.Int32(5),
+ End: scalar.Int32(6),
+ }, {
+ Start: scalar.Int32(10),
+ End: scalar.Int32(12),
+ }},
+ Value: []*descriptorpb.EnumValueDescriptorProto{{
+ Name: scalar.String("UNKNOWN"),
+ Number: scalar.Int32(0),
+ }, {
+ Name: scalar.String("FOO"),
+ Number: scalar.Int32(1),
+ }, {
+ Name: scalar.String("BAR"),
+ Number: scalar.Int32(2),
+ }, {
+ Name: scalar.String("BAD"),
+ Number: scalar.Int32(11),
+ }},
+ }},
+ },
+ wantErr: "reserved number 11",
+ }, {
+ name: "enum with reserved number",
+ fd: &descriptorpb.FileDescriptorProto{
+ Name: scalar.String("enum-with-reserved-name.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("ParentMessage"),
+ EnumType: []*descriptorpb.EnumDescriptorProto{{
+ Name: scalar.String("AnEnum"),
+ ReservedName: []string{"ABC", "XYZ"},
+ Value: []*descriptorpb.EnumValueDescriptorProto{{
+ Name: scalar.String("UNKNOWN"),
+ Number: scalar.Int32(0),
+ }, {
+ Name: scalar.String("FOO"),
+ Number: scalar.Int32(1),
+ }, {
+ Name: scalar.String("BAR"),
+ Number: scalar.Int32(2),
+ }, {
+ Name: scalar.String("XYZ"),
+ Number: scalar.Int32(3),
+ }},
+ }},
+ }},
+ },
+ wantErr: `reserved name "XYZ"`,
+ }, {
+ name: "message dependency without import",
+ deps: []*descriptorpb.FileDescriptorProto{{
+ Name: scalar.String("foo.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("Foo"),
+ }},
+ }},
+ fd: &descriptorpb.FileDescriptorProto{
+ Name: scalar.String("message-dependency-without-import.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("bar"),
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("Bar"),
+ Field: []*descriptorpb.FieldDescriptorProto{{
+ Name: scalar.String("id"),
+ Number: scalar.Int32(1),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+ }, {
+ Name: scalar.String("foo"),
+ Number: scalar.Int32(2),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+ TypeName: scalar.String(".foo.Foo"),
+ }},
+ }},
+ },
+ wantErr: "foo.Foo without import of foo.proto",
+ }, {
+ name: "enum dependency without import",
+ deps: []*descriptorpb.FileDescriptorProto{{
+ Name: scalar.String("foo.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ EnumType: []*descriptorpb.EnumDescriptorProto{{
+ Name: scalar.String("Foo"),
+ Value: []*descriptorpb.EnumValueDescriptorProto{{
+ Name: scalar.String("UNKNOWN"),
+ Number: scalar.Int32(0),
+ }},
+ }},
+ }},
+ fd: &descriptorpb.FileDescriptorProto{
+ Name: scalar.String("enum-dependency-without-import.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("bar"),
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("Bar"),
+ Field: []*descriptorpb.FieldDescriptorProto{{
+ Name: scalar.String("id"),
+ Number: scalar.Int32(1),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+ }, {
+ Name: scalar.String("foo"),
+ Number: scalar.Int32(2),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
+ TypeName: scalar.String(".foo.Foo"),
+ }},
+ }},
+ },
+ wantErr: "foo.Foo without import of foo.proto",
+ }, {
+ name: "message dependency on without import on file imported by a public import",
+ deps: []*descriptorpb.FileDescriptorProto{{
+ Name: scalar.String("foo.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("Foo"),
+ }},
+ }, {
+ Name: scalar.String("baz.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ Dependency: []string{"foo.proto"},
+ }, {
+ Name: scalar.String("old-baz.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ Dependency: []string{"baz.proto"},
+ PublicDependency: []int32{0},
+ }},
+ fd: &descriptorpb.FileDescriptorProto{
+ Name: scalar.String("message-dependency-without-import.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("bar"),
+ Dependency: []string{"old-baz.proto"},
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("Bar"),
+ Field: []*descriptorpb.FieldDescriptorProto{{
+ Name: scalar.String("id"),
+ Number: scalar.Int32(1),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+ }, {
+ Name: scalar.String("foo"),
+ Number: scalar.Int32(2),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+ TypeName: scalar.String(".foo.Foo"),
+ }},
+ }},
+ },
+ wantErr: "foo.Foo without import of foo.proto",
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ r := new(protoregistry.Files)
+ for _, dep := range tc.deps {
+ f, err := NewFile(dep, r)
+ if err != nil {
+ t.Fatalf("Error creating dependency: %v", err)
+ }
+ if err := r.Register(f); err != nil {
+ t.Fatalf("Error adding dependency: %v", err)
+ }
+ }
+ if _, err := NewFile(tc.fd, r); err == nil || !strings.Contains(err.Error(), tc.wantErr) {
+ t.Errorf("NewFile: got err = %v; want error containing %q", err, tc.wantErr)
+ }
+ })
+ }
+}
+
+// Sanity checks for well-formed descriptors. Most behavior with well-formed descriptors is covered
+// by other tests that rely on generated descriptors.
+func TestNewFile_ValidationOK(t *testing.T) {
+ testCases := []struct {
+ name string
+ deps []*descriptorpb.FileDescriptorProto
+ fd *descriptorpb.FileDescriptorProto
+ }{{
+ name: "self contained file",
+ fd: &descriptorpb.FileDescriptorProto{
+ Name: scalar.String("self-contained.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ EnumType: []*descriptorpb.EnumDescriptorProto{{
+ Name: scalar.String("TopLevelEnum"),
+ Value: []*descriptorpb.EnumValueDescriptorProto{{
+ Name: scalar.String("UNKNOWN"),
+ Number: scalar.Int32(0),
+ }},
+ }},
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("TopLevelMessage"),
+ EnumType: []*descriptorpb.EnumDescriptorProto{{
+ Name: scalar.String("NestedEnum"),
+ Value: []*descriptorpb.EnumValueDescriptorProto{{
+ Name: scalar.String("UNKNOWN"),
+ Number: scalar.Int32(0),
+ }},
+ }},
+ NestedType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("NestedMessage"),
+ }},
+ Field: []*descriptorpb.FieldDescriptorProto{{
+ Name: scalar.String("id"),
+ Number: scalar.Int32(1),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+ }, {
+ Name: scalar.String("top_level_enum"),
+ Number: scalar.Int32(2),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
+ TypeName: scalar.String(".foo.TopLevelEnum"),
+ }, {
+ Name: scalar.String("nested_enum"),
+ Number: scalar.Int32(3),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
+ TypeName: scalar.String(".foo.TopLevelMessage.NestedEnum"),
+ }, {
+ Name: scalar.String("nested_message"),
+ Number: scalar.Int32(4),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
+ TypeName: scalar.String(".foo.TopLevelMessage.NestedMessage"),
+ }},
+ }},
+ },
+ }, {
+ name: "external types with explicit import",
+ deps: []*descriptorpb.FileDescriptorProto{{
+ Name: scalar.String("foo.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("FooMessage"),
+ }},
+ EnumType: []*descriptorpb.EnumDescriptorProto{{
+ Name: scalar.String("BarEnum"),
+ Value: []*descriptorpb.EnumValueDescriptorProto{{
+ Name: scalar.String("UNKNOWN"),
+ Number: scalar.Int32(0),
+ }},
+ }},
+ }},
+ fd: &descriptorpb.FileDescriptorProto{
+ Name: scalar.String("external-types-with-explicit-import.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("bar"),
+ Dependency: []string{"foo.proto"},
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("Bar"),
+ Field: []*descriptorpb.FieldDescriptorProto{{
+ Name: scalar.String("id"),
+ Number: scalar.Int32(1),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+ }, {
+ Name: scalar.String("foo"),
+ Number: scalar.Int32(2),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+ TypeName: scalar.String(".foo.FooMessage"),
+ }, {
+ Name: scalar.String("bar"),
+ Number: scalar.Int32(3),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
+ TypeName: scalar.String(".foo.BarEnum"),
+ }},
+ }},
+ },
+ }, {
+ name: "external types with transitive public imports",
+ deps: []*descriptorpb.FileDescriptorProto{{
+ Name: scalar.String("quux.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("QuuxMessage"),
+ }},
+ }, {
+ Name: scalar.String("foo.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ Dependency: []string{"quux.proto"},
+ PublicDependency: []int32{0},
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("FooMessage"),
+ }},
+ EnumType: []*descriptorpb.EnumDescriptorProto{{
+ Name: scalar.String("BarEnum"),
+ Value: []*descriptorpb.EnumValueDescriptorProto{{
+ Name: scalar.String("UNKNOWN"),
+ Number: scalar.Int32(0),
+ }},
+ }},
+ }, {
+ Name: scalar.String("old-name.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("foo"),
+ Dependency: []string{"foo.proto"},
+ PublicDependency: []int32{0},
+ }},
+ fd: &descriptorpb.FileDescriptorProto{
+ Name: scalar.String("external-types-with-public-import.proto"),
+ Syntax: scalar.String("proto2"),
+ Package: scalar.String("bar"),
+ Dependency: []string{"old-name.proto"},
+ MessageType: []*descriptorpb.DescriptorProto{{
+ Name: scalar.String("Bar"),
+ Field: []*descriptorpb.FieldDescriptorProto{{
+ Name: scalar.String("id"),
+ Number: scalar.Int32(1),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
+ }, {
+ Name: scalar.String("foo"),
+ Number: scalar.Int32(2),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+ TypeName: scalar.String(".foo.FooMessage"),
+ }, {
+ Name: scalar.String("bar"),
+ Number: scalar.Int32(3),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
+ TypeName: scalar.String(".foo.BarEnum"),
+ }, {
+ Name: scalar.String("quux"),
+ Number: scalar.Int32(4),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
+ TypeName: scalar.String(".foo.QuuxMessage"),
+ }},
+ }},
+ },
+ }}
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ r := new(protoregistry.Files)
+ for _, dep := range tc.deps {
+ f, err := NewFile(dep, r)
+ if err != nil {
+ t.Fatalf("Error creating dependency: %v", err)
+ }
+ if err := r.Register(f); err != nil {
+ t.Fatalf("Error adding dependency: %v", err)
+ }
+ }
+ if _, err := NewFile(tc.fd, r); err != nil {
+ t.Errorf("NewFile: got err = %v", err)
+ }
+ })
+ }
+}