reflect/protodesc: split descriptor related functionality from prototype
In order to generate descriptor.proto, the generated code would want to depend
on the prototype package to construct the reflection data structures.
However, this is a problem since descriptor itself is one of the dependencies
for prototype. To break this dependency, we do the following:
* Avoid using concrete *descriptorpb.XOptions messages in the public API, and
instead just use protoreflect.ProtoMessage. We do lose some type safety here
as a result.
* Use protobuf reflection to interpret the Options message.
* Split out NewFileFromDescriptorProto into a separate protodesc package since
constructing protobuf reflection from the descriptor proto obviously depends
on the descriptor protos themselves.
As part of this CL, we check in a pre-generated version of descriptor and plugin
that supports protobuf reflection natively and switchover all usages of those
protos to the new definitions. These files were generated by protoc-gen-go
from CL/150074, but hand-modified to remove dependencies on the v1 proto runtime.
Change-Id: I81e03c42eeab480b03764e2fcbe1aae0e058fc57
Reviewed-on: https://go-review.googlesource.com/c/152020
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/reflect/prototype/protofile_desc.go b/reflect/protodesc/protodesc.go
similarity index 85%
rename from reflect/prototype/protofile_desc.go
rename to reflect/protodesc/protodesc.go
index b4ea5c3..6ab1ce8 100644
--- a/reflect/prototype/protofile_desc.go
+++ b/reflect/protodesc/protodesc.go
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package prototype
+// Package protodesc provides for converting descriptorpb.FileDescriptorProto
+// to/from the reflective protoreflect.FileDescriptor.
+package protodesc
import (
"fmt"
@@ -10,12 +12,13 @@
"strconv"
"strings"
- descriptorV1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
-
"github.com/golang/protobuf/v2/internal/encoding/text"
"github.com/golang/protobuf/v2/internal/errors"
"github.com/golang/protobuf/v2/reflect/protoreflect"
"github.com/golang/protobuf/v2/reflect/protoregistry"
+ "github.com/golang/protobuf/v2/reflect/prototype"
+
+ descriptorpb "github.com/golang/protobuf/v2/types/descriptor"
)
// TODO: Should we be responsible for validating other parts of the descriptor
@@ -41,9 +44,9 @@
// However, this will complicate future work for validation since File may now
// diverge from the stored descriptor proto (see above TODO).
-// NewFileFromDescriptorProto creates a new protoreflect.FileDescriptor from
-// the provided descriptor message. The file must represent a valid proto file
-// according to protobuf semantics.
+// NewFile creates a new protoreflect.FileDescriptor from the provided
+// file descriptor message. The file must represent a valid proto file according
+// to protobuf semantics.
//
// Any import files, enum types, or message types referenced in the file are
// resolved using the provided registry. When looking up an import file path,
@@ -52,8 +55,8 @@
//
// The caller must relinquish full ownership of the input fd and must not
// access or mutate any fields.
-func NewFileFromDescriptorProto(fd *descriptorV1.FileDescriptorProto, r *protoregistry.Files) (protoreflect.FileDescriptor, error) {
- var f File
+func NewFile(fd *descriptorpb.FileDescriptorProto, r *protoregistry.Files) (protoreflect.FileDescriptor, error) {
+ var f prototype.File
switch fd.GetSyntax() {
case "", "proto2":
f.Syntax = protoreflect.Proto2
@@ -91,7 +94,7 @@
return nil, errors.New("duplicate files for import %q", path)
}
if imp.IsWeak || imp.FileDescriptor == nil {
- imp.FileDescriptor = PlaceholderFile(path, "")
+ imp.FileDescriptor = prototype.PlaceholderFile(path, "")
}
}
@@ -113,16 +116,16 @@
return nil, err
}
- return NewFile(&f)
+ return prototype.NewFile(&f)
}
-func messagesFromDescriptorProto(mds []*descriptorV1.DescriptorProto, syntax protoreflect.Syntax, r *protoregistry.Files) (ms []Message, err error) {
+func messagesFromDescriptorProto(mds []*descriptorpb.DescriptorProto, syntax protoreflect.Syntax, r *protoregistry.Files) (ms []prototype.Message, err error) {
for _, md := range mds {
- var m Message
+ var m prototype.Message
m.Name = protoreflect.Name(md.GetName())
m.Options = md.GetOptions()
for _, fd := range md.GetField() {
- var f Field
+ var f prototype.Field
f.Name = protoreflect.Name(fd.GetName())
f.Number = protoreflect.FieldNumber(fd.GetNumber())
f.Cardinality = protoreflect.Cardinality(fd.GetLabel())
@@ -142,28 +145,29 @@
}
f.OneofName = protoreflect.Name(md.GetOneofDecl()[i].GetName())
}
+ opts, _ := f.Options.(*descriptorpb.FieldOptions)
switch f.Kind {
case protoreflect.EnumKind:
f.EnumType, err = findEnumDescriptor(fd.GetTypeName(), r)
if err != nil {
return nil, err
}
- if f.Options.GetWeak() && !f.EnumType.IsPlaceholder() {
- f.EnumType = PlaceholderEnum(f.EnumType.FullName())
+ if opts.GetWeak() && !f.EnumType.IsPlaceholder() {
+ f.EnumType = prototype.PlaceholderEnum(f.EnumType.FullName())
}
case protoreflect.MessageKind, protoreflect.GroupKind:
f.MessageType, err = findMessageDescriptor(fd.GetTypeName(), r)
if err != nil {
return nil, err
}
- if f.Options.GetWeak() && !f.MessageType.IsPlaceholder() {
- f.MessageType = PlaceholderMessage(f.MessageType.FullName())
+ if opts.GetWeak() && !f.MessageType.IsPlaceholder() {
+ f.MessageType = prototype.PlaceholderMessage(f.MessageType.FullName())
}
}
m.Fields = append(m.Fields, f)
}
for _, od := range md.GetOneofDecl() {
- m.Oneofs = append(m.Oneofs, Oneof{
+ m.Oneofs = append(m.Oneofs, prototype.Oneof{
Name: protoreflect.Name(od.GetName()),
Options: od.Options,
})
@@ -194,13 +198,13 @@
return ms, nil
}
-func enumsFromDescriptorProto(eds []*descriptorV1.EnumDescriptorProto, r *protoregistry.Files) (es []Enum, err error) {
+func enumsFromDescriptorProto(eds []*descriptorpb.EnumDescriptorProto, r *protoregistry.Files) (es []prototype.Enum, err error) {
for _, ed := range eds {
- var e Enum
+ var e prototype.Enum
e.Name = protoreflect.Name(ed.GetName())
e.Options = ed.GetOptions()
for _, vd := range ed.GetValue() {
- e.Values = append(e.Values, EnumValue{
+ e.Values = append(e.Values, prototype.EnumValue{
Name: protoreflect.Name(vd.GetName()),
Number: protoreflect.EnumNumber(vd.GetNumber()),
Options: vd.Options,
@@ -211,9 +215,9 @@
return es, nil
}
-func extensionsFromDescriptorProto(xds []*descriptorV1.FieldDescriptorProto, r *protoregistry.Files) (xs []Extension, err error) {
+func extensionsFromDescriptorProto(xds []*descriptorpb.FieldDescriptorProto, r *protoregistry.Files) (xs []prototype.Extension, err error) {
for _, xd := range xds {
- var x Extension
+ var x prototype.Extension
x.Name = protoreflect.Name(xd.GetName())
x.Number = protoreflect.FieldNumber(xd.GetNumber())
x.Cardinality = protoreflect.Cardinality(xd.GetLabel())
@@ -246,13 +250,13 @@
return xs, nil
}
-func servicesFromDescriptorProto(sds []*descriptorV1.ServiceDescriptorProto, r *protoregistry.Files) (ss []Service, err error) {
+func servicesFromDescriptorProto(sds []*descriptorpb.ServiceDescriptorProto, r *protoregistry.Files) (ss []prototype.Service, err error) {
for _, sd := range sds {
- var s Service
+ var s prototype.Service
s.Name = protoreflect.Name(sd.GetName())
s.Options = sd.GetOptions()
for _, md := range sd.GetMethod() {
- var m Method
+ var m prototype.Method
m.Name = protoreflect.Name(md.GetName())
m.Options = md.GetOptions()
m.InputType, err = findMessageDescriptor(md.GetInputType(), r)
@@ -290,7 +294,7 @@
}
return m, nil
case err == protoregistry.NotFound:
- return PlaceholderMessage(name), nil
+ return prototype.PlaceholderMessage(name), nil
default:
return nil, err
}
@@ -309,7 +313,7 @@
}
return e, nil
case err == protoregistry.NotFound:
- return PlaceholderEnum(name), nil
+ return prototype.PlaceholderEnum(name), nil
default:
return nil, err
}
diff --git a/reflect/protoreflect/type.go b/reflect/protoreflect/type.go
index 5a12921..b2c4813 100644
--- a/reflect/protoreflect/type.go
+++ b/reflect/protoreflect/type.go
@@ -102,6 +102,10 @@
// Support for this functionality is optional and may return (nil, false).
DescriptorProto() (Message, bool)
+ // TODO: Should DescriptorProto exist if prototype does not depend on
+ // the descriptor package? Should this instead be a function in the
+ // protodesc package?
+
// Options returns the descriptor options. The caller must not modify
// the returned value.
//
@@ -120,12 +124,16 @@
// | MethodDescriptor | google.protobuf.MethodOptions |
// +---------------------+------------------------------------------+
//
- // This method will never return a nil interface value, although the
- // concrete value contained in the interface may be nil (e.g.,
- // (*descpb.FileOptions)(nil)).
+ // This method may return a nil interface value if no options are present.
+ Options() ProtoMessage
+
+ // TODO: If no options are set, can Options return a typed nil-pointer
+ // using a form of dependency injection where the descriptor proto
+ // registers the option types with the prototype package?
//
- // TODO: Return ProtoMessage instead of interface{}.
- Options() interface{}
+ // However, what happens if the descriptor proto is never linked in?
+ // Then we cannot provide this guarantee.
+ // Perhaps this should return a bool as well?
doNotImplement
}
@@ -304,6 +312,11 @@
// If true, then it implies Cardinality is Repeated.
IsPacked() bool
+ // IsWeak reports whether this is a weak field, which does not impose a
+ // direct dependency on the target type.
+ // If true, then MessageDescriptor returns a placeholder type.
+ IsWeak() bool
+
// IsMap reports whether this field represents a map.
// The value type for the associated field is a Map instead of a List.
//
@@ -311,11 +324,6 @@
// and MessageDescriptor.IsMapEntry is true.
IsMap() bool
- // IsWeak reports whether this is a weak field, which does not impose a
- // direct dependency on the target type.
- // If true, then MessageDescriptor returns a placeholder type.
- IsWeak() bool
-
// Default returns the default value for scalar fields.
// For proto2, it is the default value as specified in the proto file,
// or the zero value if unspecified.
diff --git a/reflect/prototype/desc_test.go b/reflect/prototype/desc_test.go
new file mode 100644
index 0000000..50f1a6d
--- /dev/null
+++ b/reflect/prototype/desc_test.go
@@ -0,0 +1,100 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package prototype
+
+import (
+ "reflect"
+ "testing"
+
+ pref "github.com/golang/protobuf/v2/reflect/protoreflect"
+)
+
+// TestDescriptors tests that the implementations do not declare additional
+// methods that do not exist on the interface types.
+func TestDescriptors(t *testing.T) {
+ tests := []interface{}{
+ []pref.FileDescriptor{placeholderFile{}, fileDesc{}},
+ []pref.MessageDescriptor{placeholderMessage{}, standaloneMessage{}, messageDesc{}},
+ []pref.FieldDescriptor{standaloneExtension{}, fieldDesc{}, extensionDesc{}},
+ []pref.OneofDescriptor{oneofDesc{}},
+ []pref.EnumDescriptor{placeholderEnum{}, standaloneEnum{}, enumDesc{}},
+ []pref.EnumValueDescriptor{enumValueDesc{}},
+ []pref.ServiceDescriptor{serviceDesc{}},
+ []pref.MethodDescriptor{methodDesc{}},
+
+ []pref.FileImports{(*fileImports)(nil)},
+ []pref.MessageDescriptors{(*messages)(nil)},
+ []pref.FieldNumbers{(*numbers)(nil)},
+ []pref.FieldRanges{(*ranges)(nil)},
+ []pref.FieldDescriptors{(*fields)(nil), (*oneofFields)(nil)},
+ []pref.OneofDescriptors{(*oneofs)(nil)},
+ []pref.ExtensionDescriptors{(*extensions)(nil)},
+ []pref.EnumDescriptors{(*enums)(nil)},
+ []pref.EnumValueDescriptors{(*enumValues)(nil)},
+ []pref.ServiceDescriptors{(*services)(nil)},
+ []pref.MethodDescriptors{(*methods)(nil)},
+ }
+
+ for _, tt := range tests {
+ v := reflect.ValueOf(tt) // []T where T is an interface
+ ifaceType := v.Type().Elem()
+ for i := 0; i < v.Len(); i++ {
+ implType := v.Index(i).Elem().Type()
+
+ var hasName bool
+ for j := 0; j < implType.NumMethod(); j++ {
+ if name := implType.Method(j).Name; name == "Format" {
+ hasName = true
+ } else if _, ok := ifaceType.MethodByName(name); !ok {
+ t.Errorf("spurious method: %v.%v", implType, name)
+ }
+ }
+ if !hasName {
+ t.Errorf("missing method: %v.Format", implType)
+ }
+ }
+ }
+}
+
+// TestDescriptorAccessors tests that descriptorAccessors is up-to-date.
+func TestDescriptorAccessors(t *testing.T) {
+ ignore := map[string]bool{
+ "DefaultEnumValue": true,
+ "DescriptorByName": true,
+ "ProtoType": true,
+ }
+ rt := reflect.TypeOf((*pref.Descriptor)(nil)).Elem()
+ for i := 0; i < rt.NumMethod(); i++ {
+ ignore[rt.Method(i).Name] = true
+ }
+
+ for rt, m := range descriptorAccessors {
+ got := map[string]bool{}
+ for _, s := range m {
+ got[s] = true
+ }
+ want := map[string]bool{}
+ for i := 0; i < rt.NumMethod(); i++ {
+ want[rt.Method(i).Name] = true
+ }
+
+ // Check if descriptorAccessors contains a non-existent accessor.
+ // If this test fails, remove the accessor from descriptorAccessors.
+ for s := range got {
+ if !want[s] && !ignore[s] {
+ t.Errorf("%v.%v does not exist", rt, s)
+ }
+ }
+
+ // Check if there are new protoreflect interface methods that are not
+ // handled by the formatter. If this fails, either add the method to
+ // ignore or add them to descriptorAccessors.
+ for s := range want {
+ if !got[s] && !ignore[s] {
+ t.Errorf("%v.%v is not called by formatter", rt, s)
+ }
+ }
+ }
+}
diff --git a/reflect/prototype/placeholder_type.go b/reflect/prototype/placeholder_type.go
index 559dbf6..746f388 100644
--- a/reflect/prototype/placeholder_type.go
+++ b/reflect/prototype/placeholder_type.go
@@ -7,8 +7,7 @@
import (
"fmt"
- descriptorV1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
- "github.com/golang/protobuf/v2/internal/pragma"
+ pragma "github.com/golang/protobuf/v2/internal/pragma"
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
)
@@ -41,7 +40,7 @@
placeholderName
}
-func (t placeholderFile) Options() interface{} { return (*descriptorV1.FileOptions)(nil) }
+func (t placeholderFile) Options() pref.ProtoMessage { return nil }
func (t placeholderFile) Path() string { return t.path }
func (t placeholderFile) Package() pref.FullName { return t.FullName() }
func (t placeholderFile) Imports() pref.FileImports { return &emptyFiles }
@@ -57,7 +56,7 @@
placeholderName
}
-func (t placeholderMessage) Options() interface{} { return (*descriptorV1.MessageOptions)(nil) }
+func (t placeholderMessage) Options() pref.ProtoMessage { return nil }
func (t placeholderMessage) IsMapEntry() bool { return false }
func (t placeholderMessage) Fields() pref.FieldDescriptors { return &emptyFields }
func (t placeholderMessage) Oneofs() pref.OneofDescriptors { return &emptyOneofs }
@@ -73,7 +72,7 @@
placeholderName
}
-func (t placeholderEnum) Options() interface{} { return (*descriptorV1.EnumOptions)(nil) }
+func (t placeholderEnum) Options() pref.ProtoMessage { return nil }
func (t placeholderEnum) Values() pref.EnumValueDescriptors { return &emptyEnumValues }
func (t placeholderEnum) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t placeholderEnum) ProtoType(pref.EnumDescriptor) {}
diff --git a/reflect/prototype/protofile.go b/reflect/prototype/protofile.go
index a765ccd..7ff1af0 100644
--- a/reflect/prototype/protofile.go
+++ b/reflect/prototype/protofile.go
@@ -13,10 +13,7 @@
// the parent type.
package prototype
-import (
- descriptorV1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
- "github.com/golang/protobuf/v2/reflect/protoreflect"
-)
+import "github.com/golang/protobuf/v2/reflect/protoreflect"
// Every struct has a "meta" struct embedded within it as a pointer.
// The meta type provides additional data structures for efficient lookup on
@@ -44,7 +41,7 @@
Enums []Enum
Extensions []Extension
Services []Service
- Options *descriptorV1.FileOptions
+ Options protoreflect.ProtoMessage
*fileMeta
}
@@ -54,7 +51,12 @@
//
// Fields that reference an enum or message that is being declared within the
// same File can be represented using a placeholder descriptor. NewFile will
-// automatically resolve the placeholder to point to the concrete type.
+// automatically resolve the placeholder to point to a concrete descriptor.
+// Alternatively, a reference descriptor obtained via Enum.Reference or
+// Message.Reference can be used instead. The placeholder approach makes it
+// possible to declare the file descriptor as a single File literal and
+// is generally easier to use. The reference approach is more performant,
+// but also more error prone.
//
// The caller must relinquish full ownership of the input t and must not
// access or mutate any fields. The input must not contain slices that are
@@ -67,9 +69,29 @@
if err := validateFile(ft); err != nil {
return nil, err
}
+
+ // TODO: When using reference descriptors, it is vital that all enums and
+ // messages are touched so that they are initialized before returning.
+ // Otherwise, reference descriptors may still be invalid.
+ //
+ // We can remove this once validateFile is implemented, since it will
+ // inherently touch all the necessary messages and enums.
+ visitMessages(ft)
+
return ft, nil
}
+func visitMessages(d interface {
+ Enums() protoreflect.EnumDescriptors
+ Messages() protoreflect.MessageDescriptors
+}) {
+ d.Enums()
+ ms := d.Messages()
+ for i := 0; i < ms.Len(); i++ {
+ visitMessages(ms.Get(i))
+ }
+}
+
// Message is a constructor for protoreflect.MessageDescriptor.
type Message struct {
Name protoreflect.Name
@@ -79,11 +101,19 @@
Messages []Message
Enums []Enum
Extensions []Extension
- Options *descriptorV1.MessageOptions
+ Options protoreflect.ProtoMessage
*messageMeta
}
+// Reference returns m as a reference protoreflect.MessageDescriptor,
+// which can be used to satisfy internal dependencies within a proto file.
+// Methods on the returned descriptor are not valid until the file that this
+// message belongs to has been constructed via NewFile.
+func (m *Message) Reference() protoreflect.MessageDescriptor {
+ return messageDesc{m}
+}
+
// Field is a constructor for protoreflect.FieldDescriptor.
type Field struct {
Name protoreflect.Name
@@ -95,7 +125,7 @@
OneofName protoreflect.Name
MessageType protoreflect.MessageDescriptor
EnumType protoreflect.EnumDescriptor
- Options *descriptorV1.FieldOptions
+ Options protoreflect.ProtoMessage
*fieldMeta
}
@@ -103,7 +133,7 @@
// Oneof is a constructor for protoreflect.OneofDescriptor.
type Oneof struct {
Name protoreflect.Name
- Options *descriptorV1.OneofOptions
+ Options protoreflect.ProtoMessage
*oneofMeta
}
@@ -118,7 +148,7 @@
MessageType protoreflect.MessageDescriptor
EnumType protoreflect.EnumDescriptor
ExtendedType protoreflect.MessageDescriptor
- Options *descriptorV1.FieldOptions
+ Options protoreflect.ProtoMessage
*extensionMeta
}
@@ -127,16 +157,24 @@
type Enum struct {
Name protoreflect.Name
Values []EnumValue
- Options *descriptorV1.EnumOptions
+ Options protoreflect.ProtoMessage
*enumMeta
}
+// Reference returns e as a reference protoreflect.EnumDescriptor,
+// which can be used to satisfy internal dependencies within a proto file.
+// Methods on the returned descriptor are not valid until the file that this
+// enum belongs to has been constructed via NewFile.
+func (e *Enum) Reference() protoreflect.EnumDescriptor {
+ return enumDesc{e}
+}
+
// EnumValue is a constructor for protoreflect.EnumValueDescriptor.
type EnumValue struct {
Name protoreflect.Name
Number protoreflect.EnumNumber
- Options *descriptorV1.EnumValueOptions
+ Options protoreflect.ProtoMessage
*enumValueMeta
}
@@ -145,7 +183,7 @@
type Service struct {
Name protoreflect.Name
Methods []Method
- Options *descriptorV1.ServiceOptions
+ Options protoreflect.ProtoMessage
*serviceMeta
}
@@ -157,7 +195,7 @@
OutputType protoreflect.MessageDescriptor
IsStreamingClient bool
IsStreamingServer bool
- Options *descriptorV1.MethodOptions
+ Options protoreflect.ProtoMessage
*methodMeta
}
diff --git a/reflect/prototype/protofile_list.go b/reflect/prototype/protofile_list.go
index 0c9df72..b074ed9 100644
--- a/reflect/prototype/protofile_list.go
+++ b/reflect/prototype/protofile_list.go
@@ -8,15 +8,15 @@
"fmt"
"sync"
- "github.com/golang/protobuf/v2/internal/pragma"
- "github.com/golang/protobuf/v2/internal/set"
+ pragma "github.com/golang/protobuf/v2/internal/pragma"
+ pset "github.com/golang/protobuf/v2/internal/set"
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
)
type numbersMeta struct {
once sync.Once
ns []pref.FieldNumber
- nss set.Ints
+ nss pset.Ints
}
type numbers numbersMeta
diff --git a/reflect/prototype/protofile_type.go b/reflect/prototype/protofile_type.go
index d5b4250..bad93e7 100644
--- a/reflect/prototype/protofile_type.go
+++ b/reflect/prototype/protofile_type.go
@@ -10,8 +10,7 @@
"strings"
"sync"
- descriptorV1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
- "github.com/golang/protobuf/v2/internal/pragma"
+ pragma "github.com/golang/protobuf/v2/internal/pragma"
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
)
@@ -61,7 +60,7 @@
func (t fileDesc) FullName() pref.FullName { return t.f.Package }
func (t fileDesc) IsPlaceholder() bool { return false }
func (t fileDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
-func (t fileDesc) Options() interface{} { return t.f.Options }
+func (t fileDesc) Options() pref.ProtoMessage { return t.f.Options }
func (t fileDesc) Path() string { return t.f.Path }
func (t fileDesc) Package() pref.FullName { return t.f.Package }
func (t fileDesc) Imports() pref.FileImports { return (*fileImports)(&t.f.Imports) }
@@ -158,6 +157,7 @@
ms messagesMeta
es enumsMeta
xs extensionsMeta
+ mo messageOptions
}
type messageDesc struct{ m *Message }
@@ -168,8 +168,8 @@
func (t messageDesc) FullName() pref.FullName { return t.m.fullName }
func (t messageDesc) IsPlaceholder() bool { return false }
func (t messageDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
-func (t messageDesc) Options() interface{} { return t.m.Options }
-func (t messageDesc) IsMapEntry() bool { return t.m.Options.GetMapEntry() }
+func (t messageDesc) Options() pref.ProtoMessage { return t.m.Options }
+func (t messageDesc) IsMapEntry() bool { return t.m.mo.lazyInit(t).isMapEntry }
func (t messageDesc) Fields() pref.FieldDescriptors { return t.m.fs.lazyInit(t, t.m.Fields) }
func (t messageDesc) Oneofs() pref.OneofDescriptors { return t.m.os.lazyInit(t, t.m.Oneofs) }
func (t messageDesc) RequiredNumbers() pref.FieldNumbers { return t.m.ns.lazyInit(t.m.Fields) }
@@ -181,6 +181,22 @@
func (t messageDesc) ProtoType(pref.MessageDescriptor) {}
func (t messageDesc) ProtoInternal(pragma.DoNotImplement) {}
+type messageOptions struct {
+ once sync.Once
+ isMapEntry bool
+}
+
+func (p *messageOptions) lazyInit(m pref.MessageDescriptor) *messageOptions {
+ p.once.Do(func() {
+ if m.Options() != nil {
+ const mapEntryFieldNumber = 7 // google.protobuf.MessageOptions.map_entry
+ fs := m.Options().ProtoReflect().KnownFields()
+ p.isMapEntry = fs.Get(mapEntryFieldNumber).Bool()
+ }
+ })
+ return p
+}
+
type fieldMeta struct {
inheritedMeta
@@ -189,6 +205,7 @@
ot oneofReference
mt messageReference
et enumReference
+ fo fieldOptions
}
type fieldDesc struct{ f *Field }
@@ -199,14 +216,14 @@
func (t fieldDesc) FullName() pref.FullName { return t.f.fullName }
func (t fieldDesc) IsPlaceholder() bool { return false }
func (t fieldDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
-func (t fieldDesc) Options() interface{} { return t.f.Options }
+func (t fieldDesc) Options() pref.ProtoMessage { return t.f.Options }
func (t fieldDesc) Number() pref.FieldNumber { return t.f.Number }
func (t fieldDesc) Cardinality() pref.Cardinality { return t.f.Cardinality }
func (t fieldDesc) Kind() pref.Kind { return t.f.Kind }
func (t fieldDesc) JSONName() string { return t.f.js.lazyInit(t.f) }
-func (t fieldDesc) IsPacked() bool { return fieldIsPacked(t) }
-func (t fieldDesc) IsMap() bool { return isMap(t) }
-func (t fieldDesc) IsWeak() bool { return t.f.Options.GetWeak() }
+func (t fieldDesc) IsPacked() bool { return t.f.fo.lazyInit(t).isPacked }
+func (t fieldDesc) IsWeak() bool { return t.f.fo.lazyInit(t).isWeak }
+func (t fieldDesc) IsMap() bool { return t.f.fo.lazyInit(t).isMap }
func (t fieldDesc) Default() pref.Value { return t.f.dv.value(t, t.f.Default) }
func (t fieldDesc) DefaultEnumValue() pref.EnumValueDescriptor { return t.f.dv.enum(t, t.f.Default) }
func (t fieldDesc) HasDefault() bool { return t.f.Default.IsValid() }
@@ -218,44 +235,6 @@
func (t fieldDesc) ProtoType(pref.FieldDescriptor) {}
func (t fieldDesc) ProtoInternal(pragma.DoNotImplement) {}
-func fieldIsPacked(t fieldDesc) bool {
- if t.f.Options != nil && t.f.Options.Packed != nil {
- return *t.f.Options.Packed
- }
- // https://developers.google.com/protocol-buffers/docs/proto3:
- // "In proto3, repeated fields of scalar numeric types use packed
- // encoding by default."
- return (t.f.syntax == pref.Proto3 &&
- t.f.Cardinality == pref.Repeated &&
- isScalarNumeric[t.f.Kind])
-}
-
-var isScalarNumeric = map[pref.Kind]bool{
- pref.BoolKind: true,
- pref.EnumKind: true,
- pref.Int32Kind: true,
- pref.Sint32Kind: true,
- pref.Uint32Kind: true,
- pref.Int64Kind: true,
- pref.Sint64Kind: true,
- pref.Uint64Kind: true,
- pref.Sfixed32Kind: true,
- pref.Fixed32Kind: true,
- pref.FloatKind: true,
- pref.Sfixed64Kind: true,
- pref.Fixed64Kind: true,
- pref.DoubleKind: true,
-}
-
-func isMap(t pref.FieldDescriptor) bool {
- if t.Cardinality() == pref.Repeated && t.Kind() == pref.MessageKind {
- if mt := t.MessageType(); mt != nil {
- return mt.Options().(*descriptorV1.MessageOptions).GetMapEntry()
- }
- }
- return false
-}
-
type jsonName struct{ once sync.Once }
func (p *jsonName) lazyInit(f *Field) string {
@@ -301,6 +280,77 @@
return p.otyp
}
+type fieldOptions struct {
+ once sync.Once
+ isPacked bool
+ isWeak bool
+ isMap bool
+}
+
+func (p *fieldOptions) lazyInit(f pref.FieldDescriptor) *fieldOptions {
+ p.once.Do(func() {
+ if f.Cardinality() == pref.Repeated {
+ // In proto3, repeated fields of scalar numeric types use
+ // packed encoding by default.
+ // See https://developers.google.com/protocol-buffers/docs/proto3
+ if f.Syntax() == pref.Proto3 {
+ p.isPacked = isScalarNumeric[f.Kind()]
+ }
+ if f.Kind() == pref.MessageKind {
+ p.isMap = f.MessageType().IsMapEntry()
+ }
+ }
+
+ if f.Options() != nil {
+ const packedFieldNumber = 2 // google.protobuf.FieldOptions.packed
+ const weakFieldNumber = 10 // google.protobuf.FieldOptions.weak
+ fs := f.Options().ProtoReflect().KnownFields()
+ if fs.Has(packedFieldNumber) {
+ p.isPacked = fs.Get(packedFieldNumber).Bool()
+ }
+ p.isWeak = fs.Get(weakFieldNumber).Bool()
+ }
+ })
+ return p
+}
+
+// isPacked reports whether the packed options is set.
+func isPacked(m pref.ProtoMessage) (isPacked bool) {
+ if m != nil {
+ const packedFieldNumber = 2 // google.protobuf.FieldOptions.packed
+ fs := m.ProtoReflect().KnownFields()
+ isPacked = fs.Get(packedFieldNumber).Bool()
+ }
+ return isPacked
+}
+
+// isWeak reports whether the weak options is set.
+func isWeak(m pref.ProtoMessage) (isWeak bool) {
+ if m != nil {
+ const weakFieldNumber = 10 // google.protobuf.FieldOptions.weak
+ fs := m.ProtoReflect().KnownFields()
+ isWeak = fs.Get(weakFieldNumber).Bool()
+ }
+ return isWeak
+}
+
+var isScalarNumeric = map[pref.Kind]bool{
+ pref.BoolKind: true,
+ pref.EnumKind: true,
+ pref.Int32Kind: true,
+ pref.Sint32Kind: true,
+ pref.Uint32Kind: true,
+ pref.Int64Kind: true,
+ pref.Sint64Kind: true,
+ pref.Uint64Kind: true,
+ pref.Sfixed32Kind: true,
+ pref.Fixed32Kind: true,
+ pref.FloatKind: true,
+ pref.Sfixed64Kind: true,
+ pref.Fixed64Kind: true,
+ pref.DoubleKind: true,
+}
+
type oneofMeta struct {
inheritedMeta
@@ -315,7 +365,7 @@
func (t oneofDesc) FullName() pref.FullName { return t.o.fullName }
func (t oneofDesc) IsPlaceholder() bool { return false }
func (t oneofDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
-func (t oneofDesc) Options() interface{} { return t.o.Options }
+func (t oneofDesc) Options() pref.ProtoMessage { return t.o.Options }
func (t oneofDesc) Fields() pref.FieldDescriptors { return t.o.fs.lazyInit(t) }
func (t oneofDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t oneofDesc) ProtoType(pref.OneofDescriptor) {}
@@ -338,14 +388,14 @@
func (t extensionDesc) FullName() pref.FullName { return t.x.fullName }
func (t extensionDesc) IsPlaceholder() bool { return false }
func (t extensionDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
-func (t extensionDesc) Options() interface{} { return t.x.Options }
+func (t extensionDesc) Options() pref.ProtoMessage { return t.x.Options }
func (t extensionDesc) Number() pref.FieldNumber { return t.x.Number }
func (t extensionDesc) Cardinality() pref.Cardinality { return t.x.Cardinality }
func (t extensionDesc) Kind() pref.Kind { return t.x.Kind }
func (t extensionDesc) JSONName() string { return "" }
-func (t extensionDesc) IsPacked() bool { return t.x.Options.GetPacked() }
-func (t extensionDesc) IsMap() bool { return false }
+func (t extensionDesc) IsPacked() bool { return isPacked(t.Options()) }
func (t extensionDesc) IsWeak() bool { return false }
+func (t extensionDesc) IsMap() bool { return false }
func (t extensionDesc) Default() pref.Value { return t.x.dv.value(t, t.x.Default) }
func (t extensionDesc) DefaultEnumValue() pref.EnumValueDescriptor { return t.x.dv.enum(t, t.x.Default) }
func (t extensionDesc) HasDefault() bool { return t.x.Default.IsValid() }
@@ -375,7 +425,7 @@
func (t enumDesc) FullName() pref.FullName { return t.e.fullName }
func (t enumDesc) IsPlaceholder() bool { return false }
func (t enumDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
-func (t enumDesc) Options() interface{} { return t.e.Options }
+func (t enumDesc) Options() pref.ProtoMessage { return t.e.Options }
func (t enumDesc) Values() pref.EnumValueDescriptors { return t.e.vs.lazyInit(t, t.e.Values) }
func (t enumDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t enumDesc) ProtoType(pref.EnumDescriptor) {}
@@ -393,7 +443,7 @@
func (t enumValueDesc) FullName() pref.FullName { return t.v.fullName }
func (t enumValueDesc) IsPlaceholder() bool { return false }
func (t enumValueDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
-func (t enumValueDesc) Options() interface{} { return t.v.Options }
+func (t enumValueDesc) Options() pref.ProtoMessage { return t.v.Options }
func (t enumValueDesc) Number() pref.EnumNumber { return t.v.Number }
func (t enumValueDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t enumValueDesc) ProtoType(pref.EnumValueDescriptor) {}
@@ -413,7 +463,7 @@
func (t serviceDesc) FullName() pref.FullName { return t.s.fullName }
func (t serviceDesc) IsPlaceholder() bool { return false }
func (t serviceDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
-func (t serviceDesc) Options() interface{} { return t.s.Options }
+func (t serviceDesc) Options() pref.ProtoMessage { return t.s.Options }
func (t serviceDesc) Methods() pref.MethodDescriptors { return t.s.ms.lazyInit(t, t.s.Methods) }
func (t serviceDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t serviceDesc) ProtoType(pref.ServiceDescriptor) {}
@@ -434,7 +484,7 @@
func (t methodDesc) FullName() pref.FullName { return t.m.fullName }
func (t methodDesc) IsPlaceholder() bool { return false }
func (t methodDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
-func (t methodDesc) Options() interface{} { return t.m.Options }
+func (t methodDesc) Options() pref.ProtoMessage { return t.m.Options }
func (t methodDesc) InputType() pref.MessageDescriptor { return t.m.mit.lazyInit(t, &t.m.InputType) }
func (t methodDesc) OutputType() pref.MessageDescriptor { return t.m.mot.lazyInit(t, &t.m.OutputType) }
func (t methodDesc) IsStreamingClient() bool { return t.m.IsStreamingClient }
diff --git a/reflect/prototype/resolve_test.go b/reflect/prototype/resolve_test.go
new file mode 100644
index 0000000..de0b758
--- /dev/null
+++ b/reflect/prototype/resolve_test.go
@@ -0,0 +1,146 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package prototype
+
+import (
+ "testing"
+
+ pref "github.com/golang/protobuf/v2/reflect/protoreflect"
+)
+
+func TestResolve(t *testing.T) {
+ f := &File{
+ Syntax: pref.Proto2,
+ Package: "test",
+ Messages: []Message{{
+ Name: "FooMessage",
+ Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Optional, Kind: pref.BytesKind}},
+ Messages: []Message{{
+ Name: "FooMessage",
+ Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Optional, Kind: pref.BytesKind}},
+ }, {
+ Name: "BarMessage",
+ Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Optional, Kind: pref.BytesKind}},
+ }},
+ Enums: []Enum{{
+ Name: "FooEnum",
+ Values: []EnumValue{{Name: "E", Number: 0}},
+ }, {
+ Name: "BarEnum",
+ Values: []EnumValue{{Name: "E", Number: 0}},
+ }},
+ }, {
+ Name: "BarMessage",
+ Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Optional, Kind: pref.BytesKind}},
+ }},
+ Enums: []Enum{{
+ Name: "FooEnum",
+ Values: []EnumValue{{Name: "E", Number: 0}},
+ }, {
+ Name: "BarEnum",
+ Values: []EnumValue{{Name: "E", Number: 0}},
+ }},
+ }
+
+ fd, err := NewFile(f)
+ if err != nil {
+ t.Fatalf("NewFile() error: %v", err)
+ }
+
+ tests := []struct {
+ parent pref.Descriptor
+ name pref.FullName
+ want pref.Descriptor
+ }{{
+ parent: fd.Enums().Get(0),
+ name: "test.Foo",
+ want: nil,
+ }, {
+ parent: fd.Enums().Get(0),
+ name: "test.FooEnum",
+ want: fd.Enums().Get(0),
+ }, {
+ parent: fd.Enums().Get(0),
+ name: "test.BarEnum",
+ want: fd.Enums().Get(1),
+ }, {
+ parent: fd.Enums().Get(0),
+ name: "test.BarMessage",
+ want: fd.Messages().Get(1),
+ }, {
+ parent: fd.Enums().Get(0),
+ name: "test.FooMessage.BarMessage",
+ want: fd.Messages().Get(0).Messages().Get(1),
+ }, {
+ parent: fd.Enums().Get(0),
+ name: "test.FooMessage.Bar",
+ want: nil,
+ }, {
+ parent: fd.Messages().Get(1),
+ name: "test.FooMessage.BarEnum",
+ want: fd.Messages().Get(0).Enums().Get(1),
+ }, {
+ parent: fd.Messages().Get(1),
+ name: "test.FooEnum",
+ want: fd.Enums().Get(0),
+ }, {
+ parent: fd.Messages().Get(0),
+ name: "test.FooEnum",
+ want: fd.Enums().Get(0),
+ }, {
+ parent: fd.Messages().Get(0),
+ name: "test.FooEnum.NonExistent",
+ want: nil,
+ }, {
+ parent: fd.Messages().Get(0),
+ name: "test.FooMessage.FooEnum",
+ want: fd.Messages().Get(0).Enums().Get(0),
+ }, {
+ parent: fd.Messages().Get(0),
+ name: "test.FooMessage",
+ want: fd.Messages().Get(0),
+ }, {
+ parent: fd.Messages().Get(0),
+ name: "test.FooMessage.Fizz",
+ want: nil,
+ }, {
+ parent: fd.Messages().Get(0).Messages().Get(0),
+ name: "test.FooMessage.FooMessage",
+ want: fd.Messages().Get(0).Messages().Get(0),
+ }, {
+ parent: fd.Messages().Get(0).Messages().Get(0),
+ name: "test.FooMessage.BarMessage",
+ want: fd.Messages().Get(0).Messages().Get(1),
+ }, {
+ parent: fd.Messages().Get(0).Messages().Get(0),
+ name: "test.BarMessage.FooMessage",
+ want: nil,
+ }, {
+ parent: fd.Messages().Get(0).Messages().Get(0),
+ name: "test.BarMessage",
+ want: fd.Messages().Get(1),
+ }, {
+ parent: fd.Messages().Get(0).Messages().Get(0),
+ name: "test.BarMessageExtra",
+ want: nil,
+ }, {
+ parent: fd.Messages().Get(0).Messages().Get(0),
+ name: "taste.BarMessage",
+ want: nil,
+ }}
+
+ for _, tt := range tests {
+ got := resolveReference(tt.parent, tt.name)
+ if got != tt.want {
+ fullName := func(d pref.Descriptor) string {
+ if d == nil {
+ return "<nil>"
+ }
+ return string(d.FullName())
+ }
+ t.Errorf("resolveReference(%v, %v) = %v, want %v", fullName(tt.parent), tt.name, fullName(got), fullName(tt.want))
+ }
+ }
+}
diff --git a/reflect/prototype/standalone.go b/reflect/prototype/standalone.go
index fb973df..95a9619 100644
--- a/reflect/prototype/standalone.go
+++ b/reflect/prototype/standalone.go
@@ -5,7 +5,6 @@
package prototype
import (
- descriptorV1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
"github.com/golang/protobuf/v2/internal/errors"
"github.com/golang/protobuf/v2/reflect/protoreflect"
)
@@ -21,11 +20,12 @@
Fields []Field
Oneofs []Oneof
ExtensionRanges [][2]protoreflect.FieldNumber
- Options *descriptorV1.MessageOptions
+ Options protoreflect.ProtoMessage
- fields fieldsMeta
- oneofs oneofsMeta
- nums numbersMeta
+ fields fieldsMeta
+ oneofs oneofsMeta
+ nums numbersMeta
+ options messageOptions
}
// NewMessage creates a new protoreflect.MessageDescriptor.
@@ -64,7 +64,7 @@
for i, f := range t.Fields {
// Resolve placeholder messages with a concrete standalone message.
// If this fails, validateMessage will complain about it later.
- if !f.Options.GetWeak() && f.MessageType != nil && f.MessageType.IsPlaceholder() {
+ if f.MessageType != nil && f.MessageType.IsPlaceholder() && !isWeak(f.Options) {
if m, ok := ms[f.MessageType.FullName()]; ok {
t.Fields[i].MessageType = m
}
@@ -85,7 +85,7 @@
Syntax protoreflect.Syntax
FullName protoreflect.FullName
Values []EnumValue
- Options *descriptorV1.EnumOptions
+ Options protoreflect.ProtoMessage
vals enumValuesMeta
}
@@ -112,7 +112,7 @@
MessageType protoreflect.MessageDescriptor
EnumType protoreflect.EnumDescriptor
ExtendedType protoreflect.MessageDescriptor
- Options *descriptorV1.FieldOptions
+ Options protoreflect.ProtoMessage
dv defaultValue
}
diff --git a/reflect/prototype/standalone_type.go b/reflect/prototype/standalone_type.go
index 0802acd..d13b138 100644
--- a/reflect/prototype/standalone_type.go
+++ b/reflect/prototype/standalone_type.go
@@ -20,8 +20,8 @@
func (t standaloneMessage) FullName() pref.FullName { return t.m.FullName }
func (t standaloneMessage) IsPlaceholder() bool { return false }
func (t standaloneMessage) DescriptorProto() (pref.Message, bool) { return nil, false }
-func (t standaloneMessage) Options() interface{} { return t.m.Options }
-func (t standaloneMessage) IsMapEntry() bool { return t.m.Options.GetMapEntry() }
+func (t standaloneMessage) Options() pref.ProtoMessage { return t.m.Options }
+func (t standaloneMessage) IsMapEntry() bool { return t.m.options.lazyInit(t).isMapEntry }
func (t standaloneMessage) Fields() pref.FieldDescriptors { return t.m.fields.lazyInit(t, t.m.Fields) }
func (t standaloneMessage) Oneofs() pref.OneofDescriptors { return t.m.oneofs.lazyInit(t, t.m.Oneofs) }
func (t standaloneMessage) RequiredNumbers() pref.FieldNumbers { return t.m.nums.lazyInit(t.m.Fields) }
@@ -42,7 +42,7 @@
func (t standaloneEnum) FullName() pref.FullName { return t.e.FullName }
func (t standaloneEnum) IsPlaceholder() bool { return false }
func (t standaloneEnum) DescriptorProto() (pref.Message, bool) { return nil, false }
-func (t standaloneEnum) Options() interface{} { return t.e.Options }
+func (t standaloneEnum) Options() pref.ProtoMessage { return t.e.Options }
func (t standaloneEnum) Values() pref.EnumValueDescriptors { return t.e.vals.lazyInit(t, t.e.Values) }
func (t standaloneEnum) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t standaloneEnum) ProtoType(pref.EnumDescriptor) {}
@@ -57,14 +57,14 @@
func (t standaloneExtension) FullName() pref.FullName { return t.x.FullName }
func (t standaloneExtension) IsPlaceholder() bool { return false }
func (t standaloneExtension) DescriptorProto() (pref.Message, bool) { return nil, false }
-func (t standaloneExtension) Options() interface{} { return t.x.Options }
+func (t standaloneExtension) Options() pref.ProtoMessage { return t.x.Options }
func (t standaloneExtension) Number() pref.FieldNumber { return t.x.Number }
func (t standaloneExtension) Cardinality() pref.Cardinality { return t.x.Cardinality }
func (t standaloneExtension) Kind() pref.Kind { return t.x.Kind }
func (t standaloneExtension) JSONName() string { return "" }
-func (t standaloneExtension) IsPacked() bool { return t.x.Options.GetPacked() }
-func (t standaloneExtension) IsMap() bool { return false }
+func (t standaloneExtension) IsPacked() bool { return isPacked(t.Options()) }
func (t standaloneExtension) IsWeak() bool { return false }
+func (t standaloneExtension) IsMap() bool { return false }
func (t standaloneExtension) Default() pref.Value { return t.x.dv.value(t, t.x.Default) }
func (t standaloneExtension) DefaultEnumValue() pref.EnumValueDescriptor {
return t.x.dv.enum(t, t.x.Default)
diff --git a/reflect/prototype/type_test.go b/reflect/prototype/type_test.go
index 65e5d78..698f0d0 100644
--- a/reflect/prototype/type_test.go
+++ b/reflect/prototype/type_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package prototype
+package prototype_test
import (
"fmt"
@@ -13,118 +13,32 @@
"testing"
protoV1 "github.com/golang/protobuf/proto"
- descriptorV1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
-
scalar "github.com/golang/protobuf/v2/internal/scalar"
+ pdesc "github.com/golang/protobuf/v2/reflect/protodesc"
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
+ ptype "github.com/golang/protobuf/v2/reflect/prototype"
+
+ descriptorpb "github.com/golang/protobuf/v2/types/descriptor"
)
-// TestDescriptors tests that the implementations do not declare additional
-// methods that do not exist on the interface types.
-func TestDescriptors(t *testing.T) {
- tests := []interface{}{
- []pref.FileDescriptor{placeholderFile{}, fileDesc{}},
- []pref.MessageDescriptor{placeholderMessage{}, standaloneMessage{}, messageDesc{}},
- []pref.FieldDescriptor{standaloneExtension{}, fieldDesc{}, extensionDesc{}},
- []pref.OneofDescriptor{oneofDesc{}},
- []pref.EnumDescriptor{placeholderEnum{}, standaloneEnum{}, enumDesc{}},
- []pref.EnumValueDescriptor{enumValueDesc{}},
- []pref.ServiceDescriptor{serviceDesc{}},
- []pref.MethodDescriptor{methodDesc{}},
-
- []pref.FileImports{(*fileImports)(nil)},
- []pref.MessageDescriptors{(*messages)(nil)},
- []pref.FieldNumbers{(*numbers)(nil)},
- []pref.FieldRanges{(*ranges)(nil)},
- []pref.FieldDescriptors{(*fields)(nil), (*oneofFields)(nil)},
- []pref.OneofDescriptors{(*oneofs)(nil)},
- []pref.ExtensionDescriptors{(*extensions)(nil)},
- []pref.EnumDescriptors{(*enums)(nil)},
- []pref.EnumValueDescriptors{(*enumValues)(nil)},
- []pref.ServiceDescriptors{(*services)(nil)},
- []pref.MethodDescriptors{(*methods)(nil)},
- }
-
- for _, tt := range tests {
- v := reflect.ValueOf(tt) // []T where T is an interface
- ifaceType := v.Type().Elem()
- for i := 0; i < v.Len(); i++ {
- implType := v.Index(i).Elem().Type()
-
- var hasName bool
- for j := 0; j < implType.NumMethod(); j++ {
- if name := implType.Method(j).Name; name == "Format" {
- hasName = true
- } else if _, ok := ifaceType.MethodByName(name); !ok {
- t.Errorf("spurious method: %v.%v", implType, name)
- }
- }
- if !hasName {
- t.Errorf("missing method: %v.Format", implType)
- }
- }
- }
-}
-
-// TestDescriptorAccessors tests that descriptorAccessors is up-to-date.
-func TestDescriptorAccessors(t *testing.T) {
- ignore := map[string]bool{
- "DefaultEnumValue": true,
- "DescriptorByName": true,
- "ProtoType": true,
- }
- rt := reflect.TypeOf((*pref.Descriptor)(nil)).Elem()
- for i := 0; i < rt.NumMethod(); i++ {
- ignore[rt.Method(i).Name] = true
- }
-
- for rt, m := range descriptorAccessors {
- got := map[string]bool{}
- for _, s := range m {
- got[s] = true
- }
- want := map[string]bool{}
- for i := 0; i < rt.NumMethod(); i++ {
- want[rt.Method(i).Name] = true
- }
-
- // Check if descriptorAccessors contains a non-existent accessor.
- // If this test fails, remove the accessor from descriptorAccessors.
- for s := range got {
- if !want[s] && !ignore[s] {
- t.Errorf("%v.%v does not exist", rt, s)
- }
- }
-
- // Check if there are new protoreflect interface methods that are not
- // handled by the formatter. If this fails, either add the method to
- // ignore or add them to descriptorAccessors.
- for s := range want {
- if !got[s] && !ignore[s] {
- t.Errorf("%v.%v is not called by formatter", rt, s)
- }
- }
- }
-}
-
-// TODO: Test NewFileFromDescriptorProto with imported files.
+// TODO: Test protodesc.NewFile with imported files.
func TestFile(t *testing.T) {
- f1 := &File{
+ f1 := &ptype.File{
Syntax: pref.Proto2,
Path: "path/to/file.proto",
Package: "test",
- Options: &descriptorV1.FileOptions{Deprecated: scalar.Bool(true)},
- Messages: []Message{{
+ Options: &descriptorpb.FileOptions{Deprecated: scalar.Bool(true)},
+ Messages: []ptype.Message{{
Name: "A", // "test.A"
- Options: &descriptorV1.MessageOptions{
+ Options: &descriptorpb.MessageOptions{
MapEntry: scalar.Bool(true),
Deprecated: scalar.Bool(true),
},
- Fields: []Field{{
+ Fields: []ptype.Field{{
Name: "key", // "test.A.key"
Number: 1,
- Options: &descriptorV1.FieldOptions{Deprecated: scalar.Bool(true)},
+ Options: &descriptorpb.FieldOptions{Deprecated: scalar.Bool(true)},
Cardinality: pref.Optional,
Kind: pref.StringKind,
}, {
@@ -132,11 +46,11 @@
Number: 2,
Cardinality: pref.Optional,
Kind: pref.MessageKind,
- MessageType: PlaceholderMessage("test.B"),
+ MessageType: ptype.PlaceholderMessage("test.B"),
}},
}, {
Name: "B", // "test.B"
- Fields: []Field{{
+ Fields: []ptype.Field{{
Name: "field_one", // "test.B.field_one"
Number: 1,
Cardinality: pref.Optional,
@@ -150,14 +64,14 @@
Cardinality: pref.Optional,
Kind: pref.EnumKind,
Default: pref.ValueOf(pref.EnumNumber(1)),
- EnumType: PlaceholderEnum("test.E1"),
+ EnumType: ptype.PlaceholderEnum("test.E1"),
OneofName: "O2",
}, {
Name: "field_three", // "test.B.field_three"
Number: 3,
Cardinality: pref.Optional,
Kind: pref.MessageKind,
- MessageType: PlaceholderMessage("test.C"),
+ MessageType: ptype.PlaceholderMessage("test.C"),
OneofName: "O2",
}, {
Name: "field_four", // "test.B.field_four"
@@ -165,24 +79,24 @@
Number: 4,
Cardinality: pref.Repeated,
Kind: pref.MessageKind,
- MessageType: PlaceholderMessage("test.A"),
+ MessageType: ptype.PlaceholderMessage("test.A"),
}, {
Name: "field_five", // "test.B.field_five"
Number: 5,
Cardinality: pref.Repeated,
Kind: pref.Int32Kind,
- Options: &descriptorV1.FieldOptions{Packed: scalar.Bool(true)},
+ Options: &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
}, {
Name: "field_six", // "test.B.field_six"
Number: 6,
Cardinality: pref.Required,
Kind: pref.BytesKind,
}},
- Oneofs: []Oneof{
+ Oneofs: []ptype.Oneof{
{
Name: "O1", // "test.B.O1"
- Options: &descriptorV1.OneofOptions{
- UninterpretedOption: []*descriptorV1.UninterpretedOption{
+ Options: &descriptorpb.OneofOptions{
+ UninterpretedOption: []*descriptorpb.UninterpretedOption{
{StringValue: []byte("option")},
},
},
@@ -192,219 +106,219 @@
ExtensionRanges: [][2]pref.FieldNumber{{1000, 2000}, {3000, 3001}},
}, {
Name: "C", // "test.C"
- Messages: []Message{{
+ Messages: []ptype.Message{{
Name: "A", // "test.C.A"
- Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Required, Kind: pref.BytesKind, Default: pref.ValueOf([]byte("dead\xbe\xef"))}},
+ Fields: []ptype.Field{{Name: "F", Number: 1, Cardinality: pref.Required, Kind: pref.BytesKind, Default: pref.ValueOf([]byte("dead\xbe\xef"))}},
}},
- Enums: []Enum{{
+ Enums: []ptype.Enum{{
Name: "E1", // "test.C.E1"
- Values: []EnumValue{{Name: "FOO", Number: 0}, {Name: "BAR", Number: 1}},
+ Values: []ptype.EnumValue{{Name: "FOO", Number: 0}, {Name: "BAR", Number: 1}},
}},
- Extensions: []Extension{{
+ Extensions: []ptype.Extension{{
Name: "X", // "test.C.X"
Number: 1000,
Cardinality: pref.Repeated,
Kind: pref.MessageKind,
- Options: &descriptorV1.FieldOptions{Packed: scalar.Bool(false)},
- MessageType: PlaceholderMessage("test.C"),
- ExtendedType: PlaceholderMessage("test.B"),
+ Options: &descriptorpb.FieldOptions{Packed: scalar.Bool(false)},
+ MessageType: ptype.PlaceholderMessage("test.C"),
+ ExtendedType: ptype.PlaceholderMessage("test.B"),
}},
}},
- Enums: []Enum{{
+ Enums: []ptype.Enum{{
Name: "E1", // "test.E1"
- Options: &descriptorV1.EnumOptions{Deprecated: scalar.Bool(true)},
- Values: []EnumValue{
+ Options: &descriptorpb.EnumOptions{Deprecated: scalar.Bool(true)},
+ Values: []ptype.EnumValue{
{
Name: "FOO",
Number: 0,
- Options: &descriptorV1.EnumValueOptions{Deprecated: scalar.Bool(true)},
+ Options: &descriptorpb.EnumValueOptions{Deprecated: scalar.Bool(true)},
},
{Name: "BAR", Number: 1},
},
}},
- Extensions: []Extension{{
+ Extensions: []ptype.Extension{{
Name: "X", // "test.X"
Number: 1000,
Cardinality: pref.Repeated,
Kind: pref.MessageKind,
- Options: &descriptorV1.FieldOptions{Packed: scalar.Bool(true)},
- MessageType: PlaceholderMessage("test.C"),
- ExtendedType: PlaceholderMessage("test.B"),
+ Options: &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
+ MessageType: ptype.PlaceholderMessage("test.C"),
+ ExtendedType: ptype.PlaceholderMessage("test.B"),
}},
- Services: []Service{{
+ Services: []ptype.Service{{
Name: "S", // "test.S"
- Options: &descriptorV1.ServiceOptions{Deprecated: scalar.Bool(true)},
- Methods: []Method{{
+ Options: &descriptorpb.ServiceOptions{Deprecated: scalar.Bool(true)},
+ Methods: []ptype.Method{{
Name: "M", // "test.S.M"
- InputType: PlaceholderMessage("test.A"),
- OutputType: PlaceholderMessage("test.C.A"),
+ InputType: ptype.PlaceholderMessage("test.A"),
+ OutputType: ptype.PlaceholderMessage("test.C.A"),
IsStreamingClient: true,
IsStreamingServer: true,
- Options: &descriptorV1.MethodOptions{Deprecated: scalar.Bool(true)},
+ Options: &descriptorpb.MethodOptions{Deprecated: scalar.Bool(true)},
}},
}},
}
- fd1, err := NewFile(f1)
+ fd1, err := ptype.NewFile(f1)
if err != nil {
- t.Fatalf("NewFile() error: %v", err)
+ t.Fatalf("prototype.NewFile() error: %v", err)
}
- f2 := &descriptorV1.FileDescriptorProto{
+ f2 := &descriptorpb.FileDescriptorProto{
Syntax: scalar.String("proto2"),
Name: scalar.String("path/to/file.proto"),
Package: scalar.String("test"),
- Options: &descriptorV1.FileOptions{Deprecated: scalar.Bool(true)},
- MessageType: []*descriptorV1.DescriptorProto{{
+ Options: &descriptorpb.FileOptions{Deprecated: scalar.Bool(true)},
+ MessageType: []*descriptorpb.DescriptorProto{{
Name: scalar.String("A"),
- Options: &descriptorV1.MessageOptions{
+ Options: &descriptorpb.MessageOptions{
MapEntry: scalar.Bool(true),
Deprecated: scalar.Bool(true),
},
- Field: []*descriptorV1.FieldDescriptorProto{{
+ Field: []*descriptorpb.FieldDescriptorProto{{
Name: scalar.String("key"),
Number: scalar.Int32(1),
- Options: &descriptorV1.FieldOptions{Deprecated: scalar.Bool(true)},
- Label: descriptorV1.FieldDescriptorProto_Label(pref.Optional).Enum(),
- Type: descriptorV1.FieldDescriptorProto_Type(pref.StringKind).Enum(),
+ Options: &descriptorpb.FieldOptions{Deprecated: scalar.Bool(true)},
+ Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
+ Type: descriptorpb.FieldDescriptorProto_Type(pref.StringKind).Enum(),
}, {
Name: scalar.String("value"),
Number: scalar.Int32(2),
- Label: descriptorV1.FieldDescriptorProto_Label(pref.Optional).Enum(),
- Type: descriptorV1.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
+ Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
+ Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
TypeName: scalar.String(".test.B"),
}},
}, {
Name: scalar.String("B"),
- Field: []*descriptorV1.FieldDescriptorProto{{
+ Field: []*descriptorpb.FieldDescriptorProto{{
Name: scalar.String("field_one"),
Number: scalar.Int32(1),
- Label: descriptorV1.FieldDescriptorProto_Label(pref.Optional).Enum(),
- Type: descriptorV1.FieldDescriptorProto_Type(pref.StringKind).Enum(),
+ Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
+ Type: descriptorpb.FieldDescriptorProto_Type(pref.StringKind).Enum(),
DefaultValue: scalar.String("hello, \"world!\"\n"),
OneofIndex: scalar.Int32(0),
}, {
Name: scalar.String("field_two"),
JsonName: scalar.String("Field2"),
Number: scalar.Int32(2),
- Label: descriptorV1.FieldDescriptorProto_Label(pref.Optional).Enum(),
- Type: descriptorV1.FieldDescriptorProto_Type(pref.EnumKind).Enum(),
+ Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
+ Type: descriptorpb.FieldDescriptorProto_Type(pref.EnumKind).Enum(),
DefaultValue: scalar.String("BAR"),
TypeName: scalar.String(".test.E1"),
OneofIndex: scalar.Int32(1),
}, {
Name: scalar.String("field_three"),
Number: scalar.Int32(3),
- Label: descriptorV1.FieldDescriptorProto_Label(pref.Optional).Enum(),
- Type: descriptorV1.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
+ Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
+ Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
TypeName: scalar.String(".test.C"),
OneofIndex: scalar.Int32(1),
}, {
Name: scalar.String("field_four"),
JsonName: scalar.String("Field4"),
Number: scalar.Int32(4),
- Label: descriptorV1.FieldDescriptorProto_Label(pref.Repeated).Enum(),
- Type: descriptorV1.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
+ Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
+ Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
TypeName: scalar.String(".test.A"),
}, {
Name: scalar.String("field_five"),
Number: scalar.Int32(5),
- Label: descriptorV1.FieldDescriptorProto_Label(pref.Repeated).Enum(),
- Type: descriptorV1.FieldDescriptorProto_Type(pref.Int32Kind).Enum(),
- Options: &descriptorV1.FieldOptions{Packed: scalar.Bool(true)},
+ Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
+ Type: descriptorpb.FieldDescriptorProto_Type(pref.Int32Kind).Enum(),
+ Options: &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
}, {
Name: scalar.String("field_six"),
Number: scalar.Int32(6),
- Label: descriptorV1.FieldDescriptorProto_Label(pref.Required).Enum(),
- Type: descriptorV1.FieldDescriptorProto_Type(pref.BytesKind).Enum(),
+ Label: descriptorpb.FieldDescriptorProto_Label(pref.Required).Enum(),
+ Type: descriptorpb.FieldDescriptorProto_Type(pref.BytesKind).Enum(),
}},
- OneofDecl: []*descriptorV1.OneofDescriptorProto{
+ OneofDecl: []*descriptorpb.OneofDescriptorProto{
{
Name: scalar.String("O1"),
- Options: &descriptorV1.OneofOptions{
- UninterpretedOption: []*descriptorV1.UninterpretedOption{
+ Options: &descriptorpb.OneofOptions{
+ UninterpretedOption: []*descriptorpb.UninterpretedOption{
{StringValue: []byte("option")},
},
},
},
{Name: scalar.String("O2")},
},
- ExtensionRange: []*descriptorV1.DescriptorProto_ExtensionRange{
+ ExtensionRange: []*descriptorpb.DescriptorProto_ExtensionRange{
{Start: scalar.Int32(1000), End: scalar.Int32(2000)},
{Start: scalar.Int32(3000), End: scalar.Int32(3001)},
},
}, {
Name: scalar.String("C"),
- NestedType: []*descriptorV1.DescriptorProto{{
+ NestedType: []*descriptorpb.DescriptorProto{{
Name: scalar.String("A"),
- Field: []*descriptorV1.FieldDescriptorProto{{
+ Field: []*descriptorpb.FieldDescriptorProto{{
Name: scalar.String("F"),
Number: scalar.Int32(1),
- Label: descriptorV1.FieldDescriptorProto_Label(pref.Required).Enum(),
- Type: descriptorV1.FieldDescriptorProto_Type(pref.BytesKind).Enum(),
+ Label: descriptorpb.FieldDescriptorProto_Label(pref.Required).Enum(),
+ Type: descriptorpb.FieldDescriptorProto_Type(pref.BytesKind).Enum(),
DefaultValue: scalar.String(`dead\276\357`),
}},
}},
- EnumType: []*descriptorV1.EnumDescriptorProto{{
+ EnumType: []*descriptorpb.EnumDescriptorProto{{
Name: scalar.String("E1"),
- Value: []*descriptorV1.EnumValueDescriptorProto{
+ Value: []*descriptorpb.EnumValueDescriptorProto{
{Name: scalar.String("FOO"), Number: scalar.Int32(0)},
{Name: scalar.String("BAR"), Number: scalar.Int32(1)},
},
}},
- Extension: []*descriptorV1.FieldDescriptorProto{{
+ Extension: []*descriptorpb.FieldDescriptorProto{{
Name: scalar.String("X"),
Number: scalar.Int32(1000),
- Label: descriptorV1.FieldDescriptorProto_Label(pref.Repeated).Enum(),
- Type: descriptorV1.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
+ Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
+ Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
TypeName: scalar.String(".test.C"),
Extendee: scalar.String(".test.B"),
}},
}},
- EnumType: []*descriptorV1.EnumDescriptorProto{{
+ EnumType: []*descriptorpb.EnumDescriptorProto{{
Name: scalar.String("E1"),
- Options: &descriptorV1.EnumOptions{Deprecated: scalar.Bool(true)},
- Value: []*descriptorV1.EnumValueDescriptorProto{
+ Options: &descriptorpb.EnumOptions{Deprecated: scalar.Bool(true)},
+ Value: []*descriptorpb.EnumValueDescriptorProto{
{
Name: scalar.String("FOO"),
Number: scalar.Int32(0),
- Options: &descriptorV1.EnumValueOptions{Deprecated: scalar.Bool(true)},
+ Options: &descriptorpb.EnumValueOptions{Deprecated: scalar.Bool(true)},
},
{Name: scalar.String("BAR"), Number: scalar.Int32(1)},
},
}},
- Extension: []*descriptorV1.FieldDescriptorProto{{
+ Extension: []*descriptorpb.FieldDescriptorProto{{
Name: scalar.String("X"),
Number: scalar.Int32(1000),
- Label: descriptorV1.FieldDescriptorProto_Label(pref.Repeated).Enum(),
- Type: descriptorV1.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
- Options: &descriptorV1.FieldOptions{Packed: scalar.Bool(true)},
+ Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
+ Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
+ Options: &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
TypeName: scalar.String(".test.C"),
Extendee: scalar.String(".test.B"),
}},
- Service: []*descriptorV1.ServiceDescriptorProto{{
+ Service: []*descriptorpb.ServiceDescriptorProto{{
Name: scalar.String("S"),
- Options: &descriptorV1.ServiceOptions{Deprecated: scalar.Bool(true)},
- Method: []*descriptorV1.MethodDescriptorProto{{
+ Options: &descriptorpb.ServiceOptions{Deprecated: scalar.Bool(true)},
+ Method: []*descriptorpb.MethodDescriptorProto{{
Name: scalar.String("M"),
InputType: scalar.String(".test.A"),
OutputType: scalar.String(".test.C.A"),
ClientStreaming: scalar.Bool(true),
ServerStreaming: scalar.Bool(true),
- Options: &descriptorV1.MethodOptions{Deprecated: scalar.Bool(true)},
+ Options: &descriptorpb.MethodOptions{Deprecated: scalar.Bool(true)},
}},
}},
}
- fd2, err := NewFileFromDescriptorProto(f2, nil)
+ fd2, err := pdesc.NewFile(f2, nil)
if err != nil {
- t.Fatalf("NewFileFromDescriptorProto() error: %v", err)
+ t.Fatalf("protodesc.NewFile() error: %v", err)
}
tests := []struct {
name string
desc pref.FileDescriptor
}{
- {"NewFile", fd1},
- {"NewFileFromDescriptorProto", fd2},
+ {"prototype.NewFile", fd1},
+ {"protodesc.NewFile", fd2},
}
for _, tt := range tests {
tt := tt
@@ -431,7 +345,7 @@
"Path": "path/to/file.proto",
"Package": pref.FullName("test"),
"IsPlaceholder": false,
- "Options": &descriptorV1.FileOptions{Deprecated: scalar.Bool(true)},
+ "Options": &descriptorpb.FileOptions{Deprecated: scalar.Bool(true)},
"Messages": M{
"Len": 3,
"Get:0": M{
@@ -442,7 +356,7 @@
"FullName": pref.FullName("test.A"),
"IsPlaceholder": false,
"IsMapEntry": true,
- "Options": &descriptorV1.MessageOptions{
+ "Options": &descriptorpb.MessageOptions{
MapEntry: scalar.Bool(true),
Deprecated: scalar.Bool(true),
},
@@ -456,7 +370,7 @@
"Number": pref.FieldNumber(1),
"Cardinality": pref.Optional,
"Kind": pref.StringKind,
- "Options": &descriptorV1.FieldOptions{Deprecated: scalar.Bool(true)},
+ "Options": &descriptorpb.FieldOptions{Deprecated: scalar.Bool(true)},
"JSONName": "key",
"IsPacked": false,
"IsMap": false,
@@ -546,8 +460,8 @@
"ByName:O1": M{
"FullName": pref.FullName("test.B.O1"),
"Index": 0,
- "Options": &descriptorV1.OneofOptions{
- UninterpretedOption: []*descriptorV1.UninterpretedOption{
+ "Options": &descriptorpb.OneofOptions{
+ UninterpretedOption: []*descriptorpb.UninterpretedOption{
{StringValue: []byte("option")},
},
},
@@ -604,13 +518,13 @@
"Len": 1,
"Get:0": M{
"Name": pref.Name("E1"),
- "Options": &descriptorV1.EnumOptions{Deprecated: scalar.Bool(true)},
+ "Options": &descriptorpb.EnumOptions{Deprecated: scalar.Bool(true)},
"Values": M{
"Len": 2,
"ByName:Foo": nil,
"ByName:FOO": M{
"FullName": pref.FullName("test.FOO"),
- "Options": &descriptorV1.EnumValueOptions{Deprecated: scalar.Bool(true)},
+ "Options": &descriptorpb.EnumValueOptions{Deprecated: scalar.Bool(true)},
},
"ByNumber:2": nil,
"ByNumber:1": M{"FullName": pref.FullName("test.BAR")},
@@ -627,7 +541,7 @@
"IsPacked": true,
"MessageType": M{"FullName": pref.FullName("test.C"), "IsPlaceholder": false},
"ExtendedType": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
- "Options": &descriptorV1.FieldOptions{Packed: scalar.Bool(true)},
+ "Options": &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
},
},
"Services": M{
@@ -637,7 +551,7 @@
"Parent": M{"FullName": pref.FullName("test")},
"Name": pref.Name("S"),
"FullName": pref.FullName("test.S"),
- "Options": &descriptorV1.ServiceOptions{Deprecated: scalar.Bool(true)},
+ "Options": &descriptorpb.ServiceOptions{Deprecated: scalar.Bool(true)},
"Methods": M{
"Len": 1,
"Get:0": M{
@@ -648,7 +562,7 @@
"OutputType": M{"FullName": pref.FullName("test.C.A"), "IsPlaceholder": false},
"IsStreamingClient": true,
"IsStreamingServer": true,
- "Options": &descriptorV1.MethodOptions{Deprecated: scalar.Bool(true)},
+ "Options": &descriptorpb.MethodOptions{Deprecated: scalar.Bool(true)},
},
},
},
@@ -684,13 +598,20 @@
checkAccessors(t, "", reflect.ValueOf(fd), want)
}
func checkAccessors(t *testing.T, p string, rv reflect.Value, want map[string]interface{}) {
+ p0 := p
+ defer func() {
+ if ex := recover(); ex != nil {
+ t.Errorf("panic at %v: %v", p, ex)
+ }
+ }()
+
if rv.Interface() == nil {
t.Errorf("%v is nil, want non-nil", p)
return
}
for s, v := range want {
// Call the accessor method.
- p := p + "." + s
+ p = p0 + "." + s
var rets []reflect.Value
if i := strings.IndexByte(s, ':'); i >= 0 {
// Accessor method takes in a single argument, which is encoded
@@ -912,138 +833,3 @@
}
return string(b)
}
-
-func TestResolve(t *testing.T) {
- f := &File{
- Syntax: pref.Proto2,
- Package: "test",
- Messages: []Message{{
- Name: "FooMessage",
- Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Optional, Kind: pref.BytesKind}},
- Messages: []Message{{
- Name: "FooMessage",
- Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Optional, Kind: pref.BytesKind}},
- }, {
- Name: "BarMessage",
- Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Optional, Kind: pref.BytesKind}},
- }},
- Enums: []Enum{{
- Name: "FooEnum",
- Values: []EnumValue{{Name: "E", Number: 0}},
- }, {
- Name: "BarEnum",
- Values: []EnumValue{{Name: "E", Number: 0}},
- }},
- }, {
- Name: "BarMessage",
- Fields: []Field{{Name: "F", Number: 1, Cardinality: pref.Optional, Kind: pref.BytesKind}},
- }},
- Enums: []Enum{{
- Name: "FooEnum",
- Values: []EnumValue{{Name: "E", Number: 0}},
- }, {
- Name: "BarEnum",
- Values: []EnumValue{{Name: "E", Number: 0}},
- }},
- }
-
- fd, err := NewFile(f)
- if err != nil {
- t.Fatalf("NewFile() error: %v", err)
- }
-
- tests := []struct {
- parent pref.Descriptor
- name pref.FullName
- want pref.Descriptor
- }{{
- parent: fd.Enums().Get(0),
- name: "test.Foo",
- want: nil,
- }, {
- parent: fd.Enums().Get(0),
- name: "test.FooEnum",
- want: fd.Enums().Get(0),
- }, {
- parent: fd.Enums().Get(0),
- name: "test.BarEnum",
- want: fd.Enums().Get(1),
- }, {
- parent: fd.Enums().Get(0),
- name: "test.BarMessage",
- want: fd.Messages().Get(1),
- }, {
- parent: fd.Enums().Get(0),
- name: "test.FooMessage.BarMessage",
- want: fd.Messages().Get(0).Messages().Get(1),
- }, {
- parent: fd.Enums().Get(0),
- name: "test.FooMessage.Bar",
- want: nil,
- }, {
- parent: fd.Messages().Get(1),
- name: "test.FooMessage.BarEnum",
- want: fd.Messages().Get(0).Enums().Get(1),
- }, {
- parent: fd.Messages().Get(1),
- name: "test.FooEnum",
- want: fd.Enums().Get(0),
- }, {
- parent: fd.Messages().Get(0),
- name: "test.FooEnum",
- want: fd.Enums().Get(0),
- }, {
- parent: fd.Messages().Get(0),
- name: "test.FooEnum.NonExistent",
- want: nil,
- }, {
- parent: fd.Messages().Get(0),
- name: "test.FooMessage.FooEnum",
- want: fd.Messages().Get(0).Enums().Get(0),
- }, {
- parent: fd.Messages().Get(0),
- name: "test.FooMessage",
- want: fd.Messages().Get(0),
- }, {
- parent: fd.Messages().Get(0),
- name: "test.FooMessage.Fizz",
- want: nil,
- }, {
- parent: fd.Messages().Get(0).Messages().Get(0),
- name: "test.FooMessage.FooMessage",
- want: fd.Messages().Get(0).Messages().Get(0),
- }, {
- parent: fd.Messages().Get(0).Messages().Get(0),
- name: "test.FooMessage.BarMessage",
- want: fd.Messages().Get(0).Messages().Get(1),
- }, {
- parent: fd.Messages().Get(0).Messages().Get(0),
- name: "test.BarMessage.FooMessage",
- want: nil,
- }, {
- parent: fd.Messages().Get(0).Messages().Get(0),
- name: "test.BarMessage",
- want: fd.Messages().Get(1),
- }, {
- parent: fd.Messages().Get(0).Messages().Get(0),
- name: "test.BarMessageExtra",
- want: nil,
- }, {
- parent: fd.Messages().Get(0).Messages().Get(0),
- name: "taste.BarMessage",
- want: nil,
- }}
-
- for _, tt := range tests {
- got := resolveReference(tt.parent, tt.name)
- if got != tt.want {
- fullName := func(d pref.Descriptor) string {
- if d == nil {
- return "<nil>"
- }
- return string(d.FullName())
- }
- t.Errorf("resolveReference(%v, %v) = %v, want %v", fullName(tt.parent), tt.name, fullName(got), fullName(tt.want))
- }
- }
-}
diff --git a/reflect/prototype/validate.go b/reflect/prototype/validate.go
index be1090b..934237b 100644
--- a/reflect/prototype/validate.go
+++ b/reflect/prototype/validate.go
@@ -26,9 +26,7 @@
// * Placeholder messages and types may only be for weak fields.
// * Placeholder full names must be valid.
// * The name of each descriptor must be valid.
-// * Options are consistent with constructor fields:
-// Message.IsMapEntry and Message.Options.MapEntry
-// Field.IsPacked and Field.Options.Packed
+// * Options are of the correct Go type (e.g. *descriptorpb.MessageOptions).
func validateFile(t pref.FileDescriptor) error {
return nil