blob: 08a5883b388bbdfca52bf9d7749c13e35a586ca2 [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)) {
84 typ := m.Type()
85 k := m.KnownFields()
86 k.Range(func(num protoreflect.FieldNumber, value protoreflect.Value) bool {
87 field := typ.Fields().ByNumber(num)
88 f(field)
89 switch field.Kind() {
90 case protoreflect.MessageKind, protoreflect.GroupKind:
91 if field.Cardinality() == protoreflect.Repeated {
92 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}