mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-03-09 22:13:27 +00:00
reflect/protoreflect: register all desciptors in Files
This change makes it such that Files now functionally registers all descriptors in a file (not just enums, messages, extensions, and services), but also including enum values, messages fields/oneofs, and service methods. The ability to look up any descriptor by full name is needed to: 1) properly detect namespace conflicts on enum values 2) properly implement the relative name lookup logic in reflect/protodesc The approach taken: 1) Assumes that a FileDescriptor has no internal name conflicts. This will (in a future CL) be guaranteed by reflect/protodesc and is guaranteed today by protoc for generated descriptors. 2) Observes that the only declarations that can possibly conflict with another file are top-level declarations (i.e., enums, enum values, messages, extensions, and services). Enum values are annoying since they live in the same scope as the parent enum, rather than being under the enum. For the internal data structure of Files, we only register the top-level declarations. This is the bare minimum needed to detect whether the file being registered has any namespace conflicts with previously registered files. We shift the effort to lookups, where we now need to peel off the end fragments of a full name until we find a match in the internal registry. If a match is found, we may need to descend into that declaration to find a nested declaration by name. For initialization, we modify internal/filedesc to initialize the enum values for all top-level enums. This performance cost is offsetted by the fact that Files.Register now avoids internally registering nested enums, messages, and extensions. For lookup, the cost has shifted from O(1) to O(N), where N is the number of segments in the full name. Top-level descriptors still have O(1) lookup times. Nested descriptors have O(M) lookup times, where M is the level of nesting within a single file. Change-Id: I950163423431f04a503b6201ddcc20a62ccba017 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/183697 Reviewed-by: Damien Neil <dneil@google.com>
This commit is contained in:
parent
a3456c946b
commit
424139789a
@ -109,7 +109,9 @@ type (
|
||||
L1 EnumL1
|
||||
L2 *EnumL2 // protected by fileDesc.once
|
||||
}
|
||||
EnumL1 struct{}
|
||||
EnumL1 struct {
|
||||
eagerValues bool // controls whether EnumL2.Values is already populated
|
||||
}
|
||||
EnumL2 struct {
|
||||
Options func() pref.ProtoMessage
|
||||
Values EnumValues
|
||||
@ -133,11 +135,16 @@ func (ed *Enum) Options() pref.ProtoMessage {
|
||||
}
|
||||
return descopts.Enum
|
||||
}
|
||||
func (ed *Enum) Values() pref.EnumValueDescriptors { return &ed.lazyInit().Values }
|
||||
func (ed *Enum) ReservedNames() pref.Names { return &ed.lazyInit().ReservedNames }
|
||||
func (ed *Enum) ReservedRanges() pref.EnumRanges { return &ed.lazyInit().ReservedRanges }
|
||||
func (ed *Enum) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, ed) }
|
||||
func (ed *Enum) ProtoType(pref.EnumDescriptor) {}
|
||||
func (ed *Enum) Values() pref.EnumValueDescriptors {
|
||||
if ed.L1.eagerValues {
|
||||
return &ed.L2.Values
|
||||
}
|
||||
return &ed.lazyInit().Values
|
||||
}
|
||||
func (ed *Enum) ReservedNames() pref.Names { return &ed.lazyInit().ReservedNames }
|
||||
func (ed *Enum) ReservedRanges() pref.EnumRanges { return &ed.lazyInit().ReservedRanges }
|
||||
func (ed *Enum) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, ed) }
|
||||
func (ed *Enum) ProtoType(pref.EnumDescriptor) {}
|
||||
func (ed *Enum) lazyInit() *EnumL2 {
|
||||
ed.L0.ParentFile.lazyInit() // implicitly initializes L2
|
||||
return ed.L2
|
||||
|
@ -221,7 +221,8 @@ func (ed *Enum) unmarshalSeed(b []byte, nb *nameBuilder, pf *File, pd pref.Descr
|
||||
ed.L0.Parent = pd
|
||||
ed.L0.Index = i
|
||||
|
||||
for len(b) > 0 {
|
||||
var numValues int
|
||||
for b := b; len(b) > 0; {
|
||||
num, typ, n := wire.ConsumeTag(b)
|
||||
b = b[n:]
|
||||
switch typ {
|
||||
@ -231,6 +232,34 @@ func (ed *Enum) unmarshalSeed(b []byte, nb *nameBuilder, pf *File, pd pref.Descr
|
||||
switch num {
|
||||
case fieldnum.EnumDescriptorProto_Name:
|
||||
ed.L0.FullName = nb.AppendFullName(pd.FullName(), v)
|
||||
case fieldnum.EnumDescriptorProto_Value:
|
||||
numValues++
|
||||
}
|
||||
default:
|
||||
m := wire.ConsumeFieldValue(num, typ, b)
|
||||
b = b[m:]
|
||||
}
|
||||
}
|
||||
|
||||
// Only construct enum value descriptors for top-level enums since
|
||||
// they are needed for registration.
|
||||
if pd != pf {
|
||||
return
|
||||
}
|
||||
ed.L1.eagerValues = true
|
||||
ed.L2 = new(EnumL2)
|
||||
ed.L2.Values.List = make([]EnumValue, numValues)
|
||||
for i := 0; len(b) > 0; {
|
||||
num, typ, n := wire.ConsumeTag(b)
|
||||
b = b[n:]
|
||||
switch typ {
|
||||
case wire.BytesType:
|
||||
v, m := wire.ConsumeBytes(b)
|
||||
b = b[m:]
|
||||
switch num {
|
||||
case fieldnum.EnumDescriptorProto_Value:
|
||||
ed.L2.Values.List[i].unmarshalFull(v, nb, pf, ed, i)
|
||||
i++
|
||||
}
|
||||
default:
|
||||
m := wire.ConsumeFieldValue(num, typ, b)
|
||||
|
@ -187,7 +187,9 @@ func (fd *File) unmarshalFull(b []byte) {
|
||||
func (ed *Enum) unmarshalFull(b []byte, nb *nameBuilder) {
|
||||
var rawValues [][]byte
|
||||
var rawOptions []byte
|
||||
ed.L2 = new(EnumL2)
|
||||
if !ed.L1.eagerValues {
|
||||
ed.L2 = new(EnumL2)
|
||||
}
|
||||
for len(b) > 0 {
|
||||
num, typ, n := wire.ConsumeTag(b)
|
||||
b = b[n:]
|
||||
@ -210,7 +212,7 @@ func (ed *Enum) unmarshalFull(b []byte, nb *nameBuilder) {
|
||||
b = b[m:]
|
||||
}
|
||||
}
|
||||
if len(rawValues) > 0 {
|
||||
if !ed.L1.eagerValues && len(rawValues) > 0 {
|
||||
ed.L2.Values.List = make([]EnumValue, len(rawValues))
|
||||
for i, b := range rawValues {
|
||||
ed.L2.Values.List[i].unmarshalFull(b, nb, ed.L0.ParentFile, ed, i)
|
||||
|
@ -24,6 +24,8 @@ type Resolver interface {
|
||||
FindFileByPath(string) (protoreflect.FileDescriptor, error)
|
||||
FindEnumByName(protoreflect.FullName) (protoreflect.EnumDescriptor, error)
|
||||
FindMessageByName(protoreflect.FullName) (protoreflect.MessageDescriptor, error)
|
||||
|
||||
// TODO: use FindDescriptorByName instead.
|
||||
}
|
||||
|
||||
// TODO: Should we be responsible for validating other parts of the descriptor
|
||||
|
@ -43,16 +43,19 @@ var NotFound = errors.New("not found")
|
||||
// descriptors contained within them.
|
||||
// The Find and Range methods are safe for concurrent use.
|
||||
type Files struct {
|
||||
// The map of descs contains:
|
||||
// The map of descsByName contains:
|
||||
// EnumDescriptor
|
||||
// EnumValueDescriptor
|
||||
// MessageDescriptor
|
||||
// ExtensionDescriptor
|
||||
// ServiceDescriptor
|
||||
// *packageDescriptor
|
||||
//
|
||||
// Note that files are stored as a slice, since a package may contain
|
||||
// multiple files.
|
||||
descs map[protoreflect.FullName]interface{}
|
||||
// multiple files. Only top-level declarations are registered.
|
||||
// Note that enum values are in the top-level since that are in the same
|
||||
// scope as the parent enum.
|
||||
descsByName map[protoreflect.FullName]interface{}
|
||||
filesByPath map[string]protoreflect.FileDescriptor
|
||||
}
|
||||
|
||||
@ -61,22 +64,14 @@ type packageDescriptor struct {
|
||||
}
|
||||
|
||||
// NewFiles returns a registry initialized with the provided set of files.
|
||||
// If there are duplicates, the first one takes precedence.
|
||||
// Files with a namespace conflict with an pre-existing file are not registered.
|
||||
func NewFiles(files ...protoreflect.FileDescriptor) *Files {
|
||||
// TODO: Should last take precedence? This allows a user to intentionally
|
||||
// overwrite an existing registration.
|
||||
//
|
||||
// The use case is for implementing the existing v1 proto.RegisterFile
|
||||
// function where the behavior is last wins. However, it could be argued
|
||||
// that the v1 behavior is broken, and we can switch to first wins
|
||||
// without violating compatibility.
|
||||
r := new(Files)
|
||||
r.Register(files...) // ignore errors; first takes precedence
|
||||
return r
|
||||
}
|
||||
|
||||
// Register registers the provided list of file descriptors.
|
||||
// Placeholder files are ignored.
|
||||
//
|
||||
// If any descriptor within a file conflicts with the descriptor of any
|
||||
// previously registered file (e.g., two enums with the same full name),
|
||||
@ -84,8 +79,8 @@ func NewFiles(files ...protoreflect.FileDescriptor) *Files {
|
||||
//
|
||||
// It is permitted for multiple files to have the same file path.
|
||||
func (r *Files) Register(files ...protoreflect.FileDescriptor) error {
|
||||
if r.descs == nil {
|
||||
r.descs = map[protoreflect.FullName]interface{}{
|
||||
if r.descsByName == nil {
|
||||
r.descsByName = map[protoreflect.FullName]interface{}{
|
||||
"": &packageDescriptor{},
|
||||
}
|
||||
r.filesByPath = make(map[string]protoreflect.FileDescriptor)
|
||||
@ -98,51 +93,139 @@ func (r *Files) Register(files ...protoreflect.FileDescriptor) error {
|
||||
}
|
||||
return firstErr
|
||||
}
|
||||
func (r *Files) registerFile(file protoreflect.FileDescriptor) error {
|
||||
path := file.Path()
|
||||
func (r *Files) registerFile(fd protoreflect.FileDescriptor) error {
|
||||
path := fd.Path()
|
||||
if r.filesByPath[path] != nil {
|
||||
return errors.New("file %q is already registered", file.Path())
|
||||
return errors.New("file %q is already registered", fd.Path())
|
||||
}
|
||||
|
||||
for name := file.Package(); name != ""; name = name.Parent() {
|
||||
switch r.descs[name].(type) {
|
||||
for name := fd.Package(); name != ""; name = name.Parent() {
|
||||
switch r.descsByName[name].(type) {
|
||||
case nil, *packageDescriptor:
|
||||
default:
|
||||
return errors.New("file %q has a name conflict over %v", file.Path(), name)
|
||||
return errors.New("file %q has a name conflict over %v", fd.Path(), name)
|
||||
}
|
||||
}
|
||||
var err error
|
||||
rangeRegisteredDescriptors(file, func(desc protoreflect.Descriptor) {
|
||||
if r.descs[desc.FullName()] != nil {
|
||||
err = errors.New("file %q has a name conflict over %v", file.Path(), desc.FullName())
|
||||
rangeTopLevelDescriptors(fd, func(d protoreflect.Descriptor) {
|
||||
if r.descsByName[d.FullName()] != nil {
|
||||
err = errors.New("file %q has a name conflict over %v", fd.Path(), d.FullName())
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for name := file.Package(); name != ""; name = name.Parent() {
|
||||
if r.descs[name] == nil {
|
||||
r.descs[name] = &packageDescriptor{}
|
||||
for name := fd.Package(); name != ""; name = name.Parent() {
|
||||
if r.descsByName[name] == nil {
|
||||
r.descsByName[name] = &packageDescriptor{}
|
||||
}
|
||||
}
|
||||
p := r.descs[file.Package()].(*packageDescriptor)
|
||||
p.files = append(p.files, file)
|
||||
rangeRegisteredDescriptors(file, func(desc protoreflect.Descriptor) {
|
||||
r.descs[desc.FullName()] = desc
|
||||
p := r.descsByName[fd.Package()].(*packageDescriptor)
|
||||
p.files = append(p.files, fd)
|
||||
rangeTopLevelDescriptors(fd, func(d protoreflect.Descriptor) {
|
||||
r.descsByName[d.FullName()] = d
|
||||
})
|
||||
r.filesByPath[path] = file
|
||||
r.filesByPath[path] = fd
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindDescriptorByName looks up a descriptor by the full name.
|
||||
//
|
||||
// This returns (nil, NotFound) if not found.
|
||||
func (r *Files) FindDescriptorByName(name protoreflect.FullName) (protoreflect.Descriptor, error) {
|
||||
if r == nil {
|
||||
return nil, NotFound
|
||||
}
|
||||
prefix := name
|
||||
suffix := nameSuffix("")
|
||||
for prefix != "" {
|
||||
if d, ok := r.descsByName[prefix]; ok {
|
||||
switch d := d.(type) {
|
||||
case protoreflect.EnumDescriptor:
|
||||
if d.FullName() == name {
|
||||
return d, nil
|
||||
}
|
||||
case protoreflect.EnumValueDescriptor:
|
||||
if d.FullName() == name {
|
||||
return d, nil
|
||||
}
|
||||
case protoreflect.MessageDescriptor:
|
||||
if d.FullName() == name {
|
||||
return d, nil
|
||||
}
|
||||
if d := findDescriptorInMessage(d, suffix); d != nil && d.FullName() == name {
|
||||
return d, nil
|
||||
}
|
||||
case protoreflect.ExtensionDescriptor:
|
||||
if d.FullName() == name {
|
||||
return d, nil
|
||||
}
|
||||
case protoreflect.ServiceDescriptor:
|
||||
if d.FullName() == name {
|
||||
return d, nil
|
||||
}
|
||||
if d := d.Methods().ByName(suffix.Pop()); d != nil && d.FullName() == name {
|
||||
return d, nil
|
||||
}
|
||||
}
|
||||
return nil, NotFound
|
||||
}
|
||||
prefix = prefix.Parent()
|
||||
suffix = nameSuffix(name[len(prefix)+len("."):])
|
||||
}
|
||||
return nil, NotFound
|
||||
}
|
||||
|
||||
func findDescriptorInMessage(md protoreflect.MessageDescriptor, suffix nameSuffix) protoreflect.Descriptor {
|
||||
name := suffix.Pop()
|
||||
if suffix == "" {
|
||||
if ed := md.Enums().ByName(name); ed != nil {
|
||||
return ed
|
||||
}
|
||||
for i := md.Enums().Len() - 1; i >= 0; i-- {
|
||||
if vd := md.Enums().Get(i).Values().ByName(name); vd != nil {
|
||||
return vd
|
||||
}
|
||||
}
|
||||
if xd := md.Extensions().ByName(name); xd != nil {
|
||||
return xd
|
||||
}
|
||||
if fd := md.Fields().ByName(name); fd != nil {
|
||||
return fd
|
||||
}
|
||||
if od := md.Oneofs().ByName(name); od != nil {
|
||||
return od
|
||||
}
|
||||
}
|
||||
if md := md.Messages().ByName(name); md != nil {
|
||||
if suffix == "" {
|
||||
return md
|
||||
}
|
||||
return findDescriptorInMessage(md, suffix)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type nameSuffix string
|
||||
|
||||
func (s *nameSuffix) Pop() (name protoreflect.Name) {
|
||||
if i := strings.IndexByte(string(*s), '.'); i >= 0 {
|
||||
name, *s = protoreflect.Name((*s)[:i]), (*s)[i+1:]
|
||||
} else {
|
||||
name, *s = protoreflect.Name((*s)), ""
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// FindEnumByName looks up an enum by the enum's full name.
|
||||
//
|
||||
// This returns (nil, NotFound) if not found.
|
||||
//
|
||||
// Deprecated: Use FindDescriptorByName instead.
|
||||
func (r *Files) FindEnumByName(name protoreflect.FullName) (protoreflect.EnumDescriptor, error) {
|
||||
if r == nil {
|
||||
return nil, NotFound
|
||||
}
|
||||
if d, ok := r.descs[name].(protoreflect.EnumDescriptor); ok {
|
||||
d, _ := r.FindDescriptorByName(name)
|
||||
if d, ok := d.(protoreflect.EnumDescriptor); ok {
|
||||
return d, nil
|
||||
}
|
||||
return nil, NotFound
|
||||
@ -151,11 +234,11 @@ func (r *Files) FindEnumByName(name protoreflect.FullName) (protoreflect.EnumDes
|
||||
// FindMessageByName looks up a message by the message's full name.
|
||||
//
|
||||
// This returns (nil, NotFound) if not found.
|
||||
//
|
||||
// Deprecated: Use FindDescriptorByName instead.
|
||||
func (r *Files) FindMessageByName(name protoreflect.FullName) (protoreflect.MessageDescriptor, error) {
|
||||
if r == nil {
|
||||
return nil, NotFound
|
||||
}
|
||||
if d, ok := r.descs[name].(protoreflect.MessageDescriptor); ok {
|
||||
d, _ := r.FindDescriptorByName(name)
|
||||
if d, ok := d.(protoreflect.MessageDescriptor); ok {
|
||||
return d, nil
|
||||
}
|
||||
return nil, NotFound
|
||||
@ -167,11 +250,11 @@ func (r *Files) FindMessageByName(name protoreflect.FullName) (protoreflect.Mess
|
||||
// message being extended.
|
||||
//
|
||||
// This returns (nil, NotFound) if not found.
|
||||
//
|
||||
// Deprecated: Use FindDescriptorByName instead.
|
||||
func (r *Files) FindExtensionByName(name protoreflect.FullName) (protoreflect.ExtensionDescriptor, error) {
|
||||
if r == nil {
|
||||
return nil, NotFound
|
||||
}
|
||||
if d, ok := r.descs[name].(protoreflect.ExtensionDescriptor); ok {
|
||||
d, _ := r.FindDescriptorByName(name)
|
||||
if d, ok := d.(protoreflect.ExtensionDescriptor); ok {
|
||||
return d, nil
|
||||
}
|
||||
return nil, NotFound
|
||||
@ -180,11 +263,11 @@ func (r *Files) FindExtensionByName(name protoreflect.FullName) (protoreflect.Ex
|
||||
// FindServiceByName looks up a service by the service's full name.
|
||||
//
|
||||
// This returns (nil, NotFound) if not found.
|
||||
//
|
||||
// Deprecated: Use FindDescriptorByName instead.
|
||||
func (r *Files) FindServiceByName(name protoreflect.FullName) (protoreflect.ServiceDescriptor, error) {
|
||||
if r == nil {
|
||||
return nil, NotFound
|
||||
}
|
||||
if d, ok := r.descs[name].(protoreflect.ServiceDescriptor); ok {
|
||||
d, _ := r.FindDescriptorByName(name)
|
||||
if d, ok := d.(protoreflect.ServiceDescriptor); ok {
|
||||
return d, nil
|
||||
}
|
||||
return nil, NotFound
|
||||
@ -209,7 +292,7 @@ func (r *Files) RangeFiles(f func(protoreflect.FileDescriptor) bool) {
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
for _, d := range r.descs {
|
||||
for _, d := range r.descsByName {
|
||||
if p, ok := d.(*packageDescriptor); ok {
|
||||
for _, file := range p.files {
|
||||
if !f(file) {
|
||||
@ -226,7 +309,7 @@ func (r *Files) RangeFilesByPackage(name protoreflect.FullName, f func(protorefl
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
p, ok := r.descs[name].(*packageDescriptor)
|
||||
p, ok := r.descsByName[name].(*packageDescriptor)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@ -237,34 +320,29 @@ func (r *Files) RangeFilesByPackage(name protoreflect.FullName, f func(protorefl
|
||||
}
|
||||
}
|
||||
|
||||
// rangeRegisteredDescriptors iterates over all descriptors in a file which
|
||||
// will be entered into the registry: enums, messages, extensions, and services.
|
||||
func rangeRegisteredDescriptors(fd protoreflect.FileDescriptor, f func(protoreflect.Descriptor)) {
|
||||
rangeRegisteredMessageDescriptors(fd.Messages(), f)
|
||||
for i := 0; i < fd.Enums().Len(); i++ {
|
||||
e := fd.Enums().Get(i)
|
||||
f(e)
|
||||
}
|
||||
for i := 0; i < fd.Extensions().Len(); i++ {
|
||||
f(fd.Extensions().Get(i))
|
||||
}
|
||||
for i := 0; i < fd.Services().Len(); i++ {
|
||||
f(fd.Services().Get(i))
|
||||
}
|
||||
}
|
||||
func rangeRegisteredMessageDescriptors(messages protoreflect.MessageDescriptors, f func(protoreflect.Descriptor)) {
|
||||
for i := 0; i < messages.Len(); i++ {
|
||||
md := messages.Get(i)
|
||||
f(md)
|
||||
rangeRegisteredMessageDescriptors(md.Messages(), f)
|
||||
for i := 0; i < md.Enums().Len(); i++ {
|
||||
e := md.Enums().Get(i)
|
||||
f(e)
|
||||
}
|
||||
for i := 0; i < md.Extensions().Len(); i++ {
|
||||
f(md.Extensions().Get(i))
|
||||
// rangeTopLevelDescriptors iterates over all top-level descriptors in a file
|
||||
// which will be directly entered into the registry.
|
||||
func rangeTopLevelDescriptors(fd protoreflect.FileDescriptor, f func(protoreflect.Descriptor)) {
|
||||
eds := fd.Enums()
|
||||
for i := eds.Len() - 1; i >= 0; i-- {
|
||||
f(eds.Get(i))
|
||||
vds := eds.Get(i).Values()
|
||||
for i := vds.Len() - 1; i >= 0; i-- {
|
||||
f(vds.Get(i))
|
||||
}
|
||||
}
|
||||
mds := fd.Messages()
|
||||
for i := mds.Len() - 1; i >= 0; i-- {
|
||||
f(mds.Get(i))
|
||||
}
|
||||
xds := fd.Extensions()
|
||||
for i := xds.Len() - 1; i >= 0; i-- {
|
||||
f(xds.Get(i))
|
||||
}
|
||||
sds := fd.Services()
|
||||
for i := sds.Len() - 1; i >= 0; i-- {
|
||||
f(sds.Get(i))
|
||||
}
|
||||
}
|
||||
|
||||
// Type is an interface satisfied by protoreflect.EnumType,
|
||||
|
@ -18,7 +18,6 @@ import (
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
preg "google.golang.org/protobuf/reflect/protoregistry"
|
||||
|
||||
test2pb "google.golang.org/protobuf/internal/testprotos/test"
|
||||
testpb "google.golang.org/protobuf/reflect/protoregistry/testprotos"
|
||||
"google.golang.org/protobuf/types/descriptorpb"
|
||||
)
|
||||
@ -45,6 +44,10 @@ func TestFiles(t *testing.T) {
|
||||
inFile pref.FileDescriptor
|
||||
wantErr string
|
||||
}
|
||||
testFindDesc struct {
|
||||
inName pref.FullName
|
||||
wantFound bool
|
||||
}
|
||||
testRangePkg struct {
|
||||
inPkg pref.FullName
|
||||
wantFiles []file
|
||||
@ -57,6 +60,7 @@ func TestFiles(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
files []testFile
|
||||
findDescs []testFindDesc
|
||||
rangePkgs []testRangePkg
|
||||
findPaths []testFindPath
|
||||
}{{
|
||||
@ -148,10 +152,20 @@ func TestFiles(t *testing.T) {
|
||||
]
|
||||
oneof_decl: [{name:"Oneof"}]
|
||||
extension_range: [{start:1000 end:2000}]
|
||||
|
||||
enum_type: [
|
||||
{name:"Enum" value:[{name:"EnumValue" number:0}]}
|
||||
]
|
||||
nested_type: [
|
||||
{name:"Message" field:[{name:"Field" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}]}
|
||||
]
|
||||
extension: [
|
||||
{name:"Extension" number:1001 label:LABEL_OPTIONAL type:TYPE_STRING extendee:".fizz.buzz.Message"}
|
||||
]
|
||||
}]
|
||||
enum_type: [{
|
||||
name: "Enum"
|
||||
Value: [{name:"EnumValue" number:0}]
|
||||
value: [{name:"EnumValue" number:0}]
|
||||
}]
|
||||
extension: [
|
||||
{name:"Extension" number:1000 label:LABEL_OPTIONAL type:TYPE_STRING extendee:".fizz.buzz.Message"}
|
||||
@ -205,6 +219,59 @@ func TestFiles(t *testing.T) {
|
||||
}]
|
||||
`),
|
||||
}},
|
||||
findDescs: []testFindDesc{
|
||||
{inName: "fizz.buzz.message", wantFound: false},
|
||||
{inName: "fizz.buzz.Message", wantFound: true},
|
||||
{inName: "fizz.buzz.Message.X", wantFound: false},
|
||||
{inName: "fizz.buzz.Field", wantFound: false},
|
||||
{inName: "fizz.buzz.Oneof", wantFound: false},
|
||||
{inName: "fizz.buzz.Message.Field", wantFound: true},
|
||||
{inName: "fizz.buzz.Message.Field.X", wantFound: false},
|
||||
{inName: "fizz.buzz.Message.Oneof", wantFound: true},
|
||||
{inName: "fizz.buzz.Message.Oneof.X", wantFound: false},
|
||||
{inName: "fizz.buzz.Message.Message", wantFound: true},
|
||||
{inName: "fizz.buzz.Message.Message.X", wantFound: false},
|
||||
{inName: "fizz.buzz.Message.Enum", wantFound: true},
|
||||
{inName: "fizz.buzz.Message.Enum.X", wantFound: false},
|
||||
{inName: "fizz.buzz.Message.EnumValue", wantFound: true},
|
||||
{inName: "fizz.buzz.Message.EnumValue.X", wantFound: false},
|
||||
{inName: "fizz.buzz.Message.Extension", wantFound: true},
|
||||
{inName: "fizz.buzz.Message.Extension.X", wantFound: false},
|
||||
{inName: "fizz.buzz.enum", wantFound: false},
|
||||
{inName: "fizz.buzz.Enum", wantFound: true},
|
||||
{inName: "fizz.buzz.Enum.X", wantFound: false},
|
||||
{inName: "fizz.buzz.EnumValue", wantFound: true},
|
||||
{inName: "fizz.buzz.EnumValue.X", wantFound: false},
|
||||
{inName: "fizz.buzz.Enum.EnumValue", wantFound: false},
|
||||
{inName: "fizz.buzz.Extension", wantFound: true},
|
||||
{inName: "fizz.buzz.Extension.X", wantFound: false},
|
||||
{inName: "fizz.buzz.service", wantFound: false},
|
||||
{inName: "fizz.buzz.Service", wantFound: true},
|
||||
{inName: "fizz.buzz.Service.X", wantFound: false},
|
||||
{inName: "fizz.buzz.Method", wantFound: false},
|
||||
{inName: "fizz.buzz.Service.Method", wantFound: true},
|
||||
{inName: "fizz.buzz.Service.Method.X", wantFound: false},
|
||||
|
||||
{inName: "fizz.buzz.gazz", wantFound: false},
|
||||
{inName: "fizz.buzz.gazz.Enum", wantFound: true},
|
||||
{inName: "fizz.buzz.gazz.EnumValue", wantFound: true},
|
||||
{inName: "fizz.buzz.gazz.Enum.EnumValue", wantFound: false},
|
||||
|
||||
{inName: "fizz.buzz", wantFound: false},
|
||||
{inName: "fizz.buzz.Enum1", wantFound: true},
|
||||
{inName: "fizz.buzz.EnumValue1", wantFound: true},
|
||||
{inName: "fizz.buzz.Enum1.EnumValue1", wantFound: false},
|
||||
{inName: "fizz.buzz.Enum2", wantFound: true},
|
||||
{inName: "fizz.buzz.EnumValue2", wantFound: true},
|
||||
{inName: "fizz.buzz.Enum2.EnumValue2", wantFound: false},
|
||||
{inName: "fizz.buzz.Enum3", wantFound: false},
|
||||
|
||||
{inName: "", wantFound: false},
|
||||
{inName: "Message", wantFound: true},
|
||||
{inName: "Message.Message", wantFound: true},
|
||||
{inName: "Message.Message.Message", wantFound: true},
|
||||
{inName: "Message.Message.Message.Message", wantFound: false},
|
||||
},
|
||||
}}
|
||||
|
||||
sortFiles := cmpopts.SortSlices(func(x, y file) bool {
|
||||
@ -220,6 +287,14 @@ func TestFiles(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
for _, tc := range tt.findDescs {
|
||||
d, _ := files.FindDescriptorByName(tc.inName)
|
||||
gotFound := d != nil
|
||||
if gotFound != tc.wantFound {
|
||||
t.Errorf("FindDescriptorByName(%v) find mismatch: got %v, want %v", tc.inName, gotFound, tc.wantFound)
|
||||
}
|
||||
}
|
||||
|
||||
for _, tc := range tt.rangePkgs {
|
||||
var gotFiles []file
|
||||
files.RangeFilesByPackage(tc.inPkg, func(fd pref.FileDescriptor) bool {
|
||||
@ -244,64 +319,6 @@ func TestFiles(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilesLookup(t *testing.T) {
|
||||
files := []pref.FileDescriptor{
|
||||
test2pb.File_test_test_proto,
|
||||
test2pb.File_test_test_import_proto,
|
||||
}
|
||||
r := preg.NewFiles(files...)
|
||||
checkEnums := func(enums pref.EnumDescriptors) {
|
||||
for i := 0; i < enums.Len(); i++ {
|
||||
want := enums.Get(i)
|
||||
if got, err := r.FindEnumByName(want.FullName()); err != nil {
|
||||
t.Errorf("FindEnumByName(%q): unexpected error: %v", want.FullName(), err)
|
||||
} else if got != want {
|
||||
t.Errorf("FindEnumByName(%q): found descriptor %v (%p), %p", want.FullName(), got.FullName(), got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
checkExtensions := func(exts pref.ExtensionDescriptors) {
|
||||
for i := 0; i < exts.Len(); i++ {
|
||||
want := exts.Get(i)
|
||||
if got, err := r.FindExtensionByName(want.FullName()); err != nil {
|
||||
t.Errorf("FindExtensionByName(%q): unexpected error: %v", want.FullName(), err)
|
||||
} else if got != want {
|
||||
t.Errorf("FindExtensionByName(%q): found descriptor %v (%p), %p", want.FullName(), got.FullName(), got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
var checkMessages func(pref.MessageDescriptors)
|
||||
checkMessages = func(messages pref.MessageDescriptors) {
|
||||
for i := 0; i < messages.Len(); i++ {
|
||||
want := messages.Get(i)
|
||||
if got, err := r.FindMessageByName(want.FullName()); err != nil {
|
||||
t.Errorf("FindMessageByName(%q): unexpected error: %v", want.FullName(), err)
|
||||
} else if got != want {
|
||||
t.Errorf("FindMessageByName(%q): found descriptor %v (%p), %p", want.FullName(), got.FullName(), got, want)
|
||||
}
|
||||
checkEnums(want.Enums())
|
||||
checkExtensions(want.Extensions())
|
||||
checkMessages(want.Messages())
|
||||
}
|
||||
}
|
||||
checkServices := func(services pref.ServiceDescriptors) {
|
||||
for i := 0; i < services.Len(); i++ {
|
||||
want := services.Get(i)
|
||||
if got, err := r.FindServiceByName(want.FullName()); err != nil {
|
||||
t.Errorf("FindServiceByName(%q): unexpected error: %v", want.FullName(), err)
|
||||
} else if got != want {
|
||||
t.Errorf("FindServiceByName(%q): found descriptor %v (%p), %p", want.FullName(), got.FullName(), got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, fd := range files {
|
||||
checkEnums(fd.Enums())
|
||||
checkExtensions(fd.Extensions())
|
||||
checkMessages(fd.Messages())
|
||||
checkServices(fd.Services())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypes(t *testing.T) {
|
||||
mt1 := pimpl.Export{}.MessageTypeOf(&testpb.Message1{})
|
||||
et1 := pimpl.Export{}.EnumTypeOf(testpb.Enum1_ONE)
|
||||
|
Loading…
x
Reference in New Issue
Block a user