blob: a02036b5aef1d6c9a00add0971391c77650c7973 [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 Tsai40692112019-02-27 20:25:51 -080023 got := protodesc.ToFileDescriptorProto(testpb.File_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
71}
72
73// visitFields calls f for every field set in m and its children.
74func visitFields(m protoreflect.Message, f func(protoreflect.FieldDescriptor)) {
75 typ := m.Type()
76 k := m.KnownFields()
77 k.Range(func(num protoreflect.FieldNumber, value protoreflect.Value) bool {
78 field := typ.Fields().ByNumber(num)
79 f(field)
80 switch field.Kind() {
81 case protoreflect.MessageKind, protoreflect.GroupKind:
82 if field.Cardinality() == protoreflect.Repeated {
83 for i, list := 0, value.List(); i < list.Len(); i++ {
84 visitFields(list.Get(i).Message(), f)
85 }
86 } else {
87 visitFields(value.Message(), f)
88 }
89 }
90 return true
91 })
92}