blob: dd58fd09d41ce8b28c00823c1b4d1dbfb91a925c [file] [log] [blame]
Damien Neile475eaa2019-01-26 14:24:59 -08001package fileinit_test
2
3import (
4 "bytes"
5 "compress/gzip"
6 "io/ioutil"
7 "testing"
8
9 proto "github.com/golang/protobuf/proto"
10 testpb "github.com/golang/protobuf/v2/internal/testprotos/test"
11 "github.com/golang/protobuf/v2/reflect/protodesc"
12 "github.com/golang/protobuf/v2/reflect/protoreflect"
13 descriptorpb "github.com/golang/protobuf/v2/types/descriptor"
14)
15
16func TestInit(t *testing.T) {
17 // Compare the FileDescriptorProto for the same test file from two different sources:
18 //
19 // 1. The result of passing the fileinit-produced FileDescriptor through protodesc.
20 // 2. The protoc-generated wire-encoded message.
21 //
22 // This serves as a test of both fileinit and protodesc.
Joe Tsai19058432019-02-27 21:46:29 -080023 got := protodesc.ToFileDescriptorProto(testpb.File_test_test_proto)
Damien Neile475eaa2019-01-26 14:24:59 -080024
25 want := &descriptorpb.FileDescriptorProto{}
26 zb, _ := (&testpb.TestAllTypes{}).Descriptor()
27 r, _ := gzip.NewReader(bytes.NewBuffer(zb))
28 b, _ := ioutil.ReadAll(r)
29 if err := proto.Unmarshal(b, want); err != nil {
30 t.Fatal(err)
31 }
32
33 if !proto.Equal(got, want) {
34 t.Errorf("protodesc.ToFileDescriptorProto(testpb.Test_protoFile) is not equal to the protoc-generated FileDescriptorProto for internal/testprotos/test/test.proto")
35 }
36
37 // Verify that the test proto file provides exhaustive coverage of all descriptor fields.
38 seen := make(map[protoreflect.FullName]bool)
39 visitFields(want.ProtoReflect(), func(field protoreflect.FieldDescriptor) {
40 seen[field.FullName()] = true
41 })
42 ignore := map[protoreflect.FullName]bool{
43 // The protoreflect descriptors don't include source info.
44 "google.protobuf.FileDescriptorProto.source_code_info": true,
45 "google.protobuf.FileDescriptorProto.syntax": true,
46
47 // TODO: Test oneof and extension options. Testing these requires extending the
48 // options messages (because they contain no user-settable fields), but importing
49 // decriptor.proto from test.proto currently causes an import cycle. Add test
50 // cases when that import cycle has been fixed.
51 "google.protobuf.OneofDescriptorProto.options": true,
52 }
53 for _, messageName := range []protoreflect.Name{
54 "FileDescriptorProto",
55 "DescriptorProto",
56 "FieldDescriptorProto",
57 "OneofDescriptorProto",
58 "EnumDescriptorProto",
59 "EnumValueDescriptorProto",
60 "ServiceDescriptorProto",
61 "MethodDescriptorProto",
62 } {
Joe Tsai40692112019-02-27 20:25:51 -080063 message := descriptorpb.File_google_protobuf_descriptor_proto.Messages().ByName(messageName)
Damien Neile475eaa2019-01-26 14:24:59 -080064 for i, fields := 0, message.Fields(); i < fields.Len(); i++ {
65 if name := fields.Get(i).FullName(); !seen[name] && !ignore[name] {
66 t.Errorf("No test for descriptor field: %v", name)
67 }
68 }
69 }
70
Joe Tsai4532dd72019-03-19 17:04:06 -070071 // Verify that message descriptors for map entries have no Go type info.
72 mapEntryName := protoreflect.FullName("goproto.proto.test.TestAllTypes.MapInt32Int32Entry")
Joe Tsaid24bc722019-04-15 23:39:09 -070073 d := testpb.File_test_test_proto.Messages().ByName("TestAllTypes").Fields().ByName("map_int32_int32").Message()
Damien Neil2300c182019-04-15 13:05:13 -070074 if gotName, wantName := d.FullName(), mapEntryName; gotName != wantName {
75 t.Fatalf("looked up wrong descriptor: got %v, want %v", gotName, wantName)
Joe Tsai4532dd72019-03-19 17:04:06 -070076 }
77 if _, ok := d.(protoreflect.MessageType); ok {
78 t.Errorf("message descriptor for %v must not implement protoreflect.MessageType", mapEntryName)
79 }
Damien Neile475eaa2019-01-26 14:24:59 -080080}
81
82// visitFields calls f for every field set in m and its children.
83func visitFields(m protoreflect.Message, f func(protoreflect.FieldDescriptor)) {
Joe Tsai0fc49f82019-05-01 12:29:25 -070084 fieldDescs := m.Descriptor().Fields()
Damien Neile475eaa2019-01-26 14:24:59 -080085 k := m.KnownFields()
86 k.Range(func(num protoreflect.FieldNumber, value protoreflect.Value) bool {
Joe Tsai0fc49f82019-05-01 12:29:25 -070087 field := fieldDescs.ByNumber(num)
Damien Neile475eaa2019-01-26 14:24:59 -080088 f(field)
89 switch field.Kind() {
90 case protoreflect.MessageKind, protoreflect.GroupKind:
Joe Tsaiac31a352019-05-13 14:32:56 -070091 if field.IsList() {
Damien Neile475eaa2019-01-26 14:24:59 -080092 for i, list := 0, value.List(); i < list.Len(); i++ {
93 visitFields(list.Get(i).Message(), f)
94 }
95 } else {
96 visitFields(value.Message(), f)
97 }
98 }
99 return true
100 })
101}
Damien Neil82a03062019-05-08 07:52:49 -0700102
103func TestWeakInit(t *testing.T) {
104 file := testpb.File_test_test_proto
105 fd := file.Messages().ByName("TestWeak").Fields().ByName("weak_message")
106 if want, got := fd.IsWeak(), true; got != want {
107 t.Errorf("field %v: IsWeak() = %v, want %v", fd.FullName(), want, got)
108 }
109 if want, got := fd.Message().IsPlaceholder(), false; got != want {
110 t.Errorf("field %v: Message.IsPlaceholder() = %v, want %v", fd.FullName(), want, got)
111 }
112 if fd.Message().Fields().Len() == 0 {
113 t.Errorf("field %v: Message().Fields().Len() == 0, want >0", fd.FullName())
114 }
115}