protobuf-go/internal/impl/legacy_test.go
Damien Neil 204f1c0ad8 reflect/protoreflect: add Descriptor.Options method
Add a method to fetch descriptor options. Since options are proto
messages (e.g., google.protobuf.FieldOptions), and proto message
packages depend on the protoreflect package, returning the actual option
type would cause a dependency cycle. Instead, we return an interface
value which can be type asserted to the appropriate concrete type.

Add options support to the prototype package.

Some of the prototype constructors included fields (such as
Field.IsPacked) which represent information from the options
(such as google.protobuf.FieldOptions.packed). To avoid confusion about
the canonical source of information, drop these fields in favor of the
options.

Drop the unimplemented Descriptor.DescriptorOptionsProto.

Change-Id: I66579b6a7d10d99eb6977402a247306a78913e74
Reviewed-on: https://go-review.googlesource.com/c/144277
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2018-10-23 23:44:11 +00:00

136 lines
4.6 KiB
Go

// 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 impl
import (
"reflect"
"testing"
"github.com/golang/protobuf/v2/internal/pragma"
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
ptype "github.com/golang/protobuf/v2/reflect/prototype"
"github.com/google/go-cmp/cmp"
)
func mustLoadFileDesc(b []byte) pref.FileDescriptor {
fd, err := ptype.NewFileFromDescriptorProto(loadFileDesc(b), nil)
if err != nil {
panic(err)
}
return fd
}
var fileDescLP2 = mustLoadFileDesc(LP2FileDescriptor)
var fileDescLP3 = mustLoadFileDesc(LP3FileDescriptor)
func TestLegacy(t *testing.T) {
tests := []struct {
got pref.Descriptor
want pref.Descriptor
}{{
got: loadEnumDesc(reflect.TypeOf(LP2MapEnum(0))),
want: fileDescLP2.Enums().ByName("LP2MapEnum"),
}, {
got: loadEnumDesc(reflect.TypeOf(LP2SiblingEnum(0))),
want: fileDescLP2.Enums().ByName("LP2SiblingEnum"),
}, {
got: loadEnumDesc(reflect.TypeOf(LP2Message_LP2ChildEnum(0))),
want: fileDescLP2.Messages().ByName("LP2Message").Enums().ByName("LP2ChildEnum"),
}, {
got: loadMessageDesc(reflect.TypeOf(new(LP2Message))),
want: fileDescLP2.Messages().ByName("LP2Message"),
}, {
got: loadMessageDesc(reflect.TypeOf(new(LP2Message_LP2ChildMessage))),
want: fileDescLP2.Messages().ByName("LP2Message").Messages().ByName("LP2ChildMessage"),
}, {
got: loadMessageDesc(reflect.TypeOf(new(LP2Message_LP2NamedGroup))),
want: fileDescLP2.Messages().ByName("LP2Message").Messages().ByName("LP2NamedGroup"),
}, {
got: loadMessageDesc(reflect.TypeOf(new(LP2Message_OptionalGroup))),
want: fileDescLP2.Messages().ByName("LP2Message").Messages().ByName("OptionalGroup"),
}, {
got: loadMessageDesc(reflect.TypeOf(new(LP2Message_RequiredGroup))),
want: fileDescLP2.Messages().ByName("LP2Message").Messages().ByName("RequiredGroup"),
}, {
got: loadMessageDesc(reflect.TypeOf(new(LP2Message_RepeatedGroup))),
want: fileDescLP2.Messages().ByName("LP2Message").Messages().ByName("RepeatedGroup"),
}, {
got: loadMessageDesc(reflect.TypeOf(new(LP2SiblingMessage))),
want: fileDescLP2.Messages().ByName("LP2SiblingMessage"),
}, {
got: loadEnumDesc(reflect.TypeOf(LP3SiblingEnum(0))),
want: fileDescLP3.Enums().ByName("LP3SiblingEnum"),
}, {
got: loadEnumDesc(reflect.TypeOf(LP3Message_LP3ChildEnum(0))),
want: fileDescLP3.Messages().ByName("LP3Message").Enums().ByName("LP3ChildEnum"),
}, {
got: loadMessageDesc(reflect.TypeOf(new(LP3Message))),
want: fileDescLP3.Messages().ByName("LP3Message"),
}, {
got: loadMessageDesc(reflect.TypeOf(new(LP3Message_LP3ChildMessage))),
want: fileDescLP3.Messages().ByName("LP3Message").Messages().ByName("LP3ChildMessage"),
}, {
got: loadMessageDesc(reflect.TypeOf(new(LP3SiblingMessage))),
want: fileDescLP3.Messages().ByName("LP3SiblingMessage"),
}}
type list interface {
Len() int
pragma.DoNotImplement
}
opts := cmp.Options{
cmp.Transformer("", func(x list) []interface{} {
out := make([]interface{}, x.Len())
v := reflect.ValueOf(x)
for i := 0; i < x.Len(); i++ {
m := v.MethodByName("Get")
out[i] = m.Call([]reflect.Value{reflect.ValueOf(i)})[0].Interface()
}
return out
}),
cmp.Transformer("", func(x pref.Descriptor) map[string]interface{} {
out := make(map[string]interface{})
v := reflect.ValueOf(x)
for i := 0; i < v.NumMethod(); i++ {
name := v.Type().Method(i).Name
if m := v.Method(i); m.Type().NumIn() == 0 && m.Type().NumOut() == 1 {
switch name {
case "Index":
// Ignore index since legacy descriptors have no parent.
case "Options":
// Ignore descriptor options since protos are not cmperable.
case "Messages", "Enums":
// Ignore nested message and enum declarations since
// legacy descriptors are all created standalone.
case "OneofType", "ExtendedType", "MessageType", "EnumType":
// Avoid descending into a dependency to avoid a cycle.
// Just record the full name if available.
//
// TODO: Cycle support in cmp would be useful here.
v := m.Call(nil)[0]
if !v.IsNil() {
out[name] = v.Interface().(pref.Descriptor).FullName()
}
default:
out[name] = m.Call(nil)[0].Interface()
}
}
}
return out
}),
cmp.Transformer("", func(v pref.Value) interface{} {
return v.Interface()
}),
}
for _, tt := range tests {
t.Run(string(tt.want.FullName()), func(t *testing.T) {
if diff := cmp.Diff(&tt.want, &tt.got, opts); diff != "" {
t.Errorf("descriptor mismatch (-want, +got):\n%s", diff)
}
})
}
}