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