blob: 3a4f5aeb31d973a6e620ef42a564209243d836c5 [file] [log] [blame]
Joe Tsaid8881392019-06-06 13:01:53 -07001// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package filedesc_test
Damien Neile475eaa2019-01-26 14:24:59 -08006
7import (
8 "bytes"
9 "compress/gzip"
10 "io/ioutil"
11 "testing"
12
Joe Tsai8d30bbe2019-05-16 15:53:25 -070013 "google.golang.org/protobuf/proto"
Damien Neile89e6242019-05-13 23:55:40 -070014 "google.golang.org/protobuf/reflect/protodesc"
15 "google.golang.org/protobuf/reflect/protoreflect"
Joe Tsaia95b29f2019-05-16 12:47:20 -070016
17 testpb "google.golang.org/protobuf/internal/testprotos/test"
18 "google.golang.org/protobuf/types/descriptorpb"
Damien Neile475eaa2019-01-26 14:24:59 -080019)
20
21func TestInit(t *testing.T) {
22 // Compare the FileDescriptorProto for the same test file from two different sources:
23 //
Joe Tsaid8881392019-06-06 13:01:53 -070024 // 1. The result of passing the filedesc-produced FileDescriptor through protodesc.
Damien Neile475eaa2019-01-26 14:24:59 -080025 // 2. The protoc-generated wire-encoded message.
26 //
Joe Tsaid8881392019-06-06 13:01:53 -070027 // This serves as a test of both filedesc and protodesc.
Joe Tsai19058432019-02-27 21:46:29 -080028 got := protodesc.ToFileDescriptorProto(testpb.File_test_test_proto)
Damien Neile475eaa2019-01-26 14:24:59 -080029
30 want := &descriptorpb.FileDescriptorProto{}
31 zb, _ := (&testpb.TestAllTypes{}).Descriptor()
32 r, _ := gzip.NewReader(bytes.NewBuffer(zb))
33 b, _ := ioutil.ReadAll(r)
34 if err := proto.Unmarshal(b, want); err != nil {
35 t.Fatal(err)
36 }
37
38 if !proto.Equal(got, want) {
39 t.Errorf("protodesc.ToFileDescriptorProto(testpb.Test_protoFile) is not equal to the protoc-generated FileDescriptorProto for internal/testprotos/test/test.proto")
40 }
41
42 // Verify that the test proto file provides exhaustive coverage of all descriptor fields.
43 seen := make(map[protoreflect.FullName]bool)
44 visitFields(want.ProtoReflect(), func(field protoreflect.FieldDescriptor) {
45 seen[field.FullName()] = true
46 })
47 ignore := map[protoreflect.FullName]bool{
48 // The protoreflect descriptors don't include source info.
49 "google.protobuf.FileDescriptorProto.source_code_info": true,
50 "google.protobuf.FileDescriptorProto.syntax": true,
51
52 // TODO: Test oneof and extension options. Testing these requires extending the
53 // options messages (because they contain no user-settable fields), but importing
54 // decriptor.proto from test.proto currently causes an import cycle. Add test
55 // cases when that import cycle has been fixed.
56 "google.protobuf.OneofDescriptorProto.options": true,
57 }
58 for _, messageName := range []protoreflect.Name{
59 "FileDescriptorProto",
60 "DescriptorProto",
61 "FieldDescriptorProto",
62 "OneofDescriptorProto",
63 "EnumDescriptorProto",
64 "EnumValueDescriptorProto",
65 "ServiceDescriptorProto",
66 "MethodDescriptorProto",
67 } {
Joe Tsai40692112019-02-27 20:25:51 -080068 message := descriptorpb.File_google_protobuf_descriptor_proto.Messages().ByName(messageName)
Damien Neile475eaa2019-01-26 14:24:59 -080069 for i, fields := 0, message.Fields(); i < fields.Len(); i++ {
70 if name := fields.Get(i).FullName(); !seen[name] && !ignore[name] {
71 t.Errorf("No test for descriptor field: %v", name)
72 }
73 }
74 }
75
Joe Tsai4532dd72019-03-19 17:04:06 -070076 // Verify that message descriptors for map entries have no Go type info.
77 mapEntryName := protoreflect.FullName("goproto.proto.test.TestAllTypes.MapInt32Int32Entry")
Joe Tsaid24bc722019-04-15 23:39:09 -070078 d := testpb.File_test_test_proto.Messages().ByName("TestAllTypes").Fields().ByName("map_int32_int32").Message()
Damien Neil2300c182019-04-15 13:05:13 -070079 if gotName, wantName := d.FullName(), mapEntryName; gotName != wantName {
80 t.Fatalf("looked up wrong descriptor: got %v, want %v", gotName, wantName)
Joe Tsai4532dd72019-03-19 17:04:06 -070081 }
82 if _, ok := d.(protoreflect.MessageType); ok {
83 t.Errorf("message descriptor for %v must not implement protoreflect.MessageType", mapEntryName)
84 }
Damien Neile475eaa2019-01-26 14:24:59 -080085}
86
87// visitFields calls f for every field set in m and its children.
88func visitFields(m protoreflect.Message, f func(protoreflect.FieldDescriptor)) {
Joe Tsai378c1322019-04-25 23:48:08 -070089 m.Range(func(fd protoreflect.FieldDescriptor, value protoreflect.Value) bool {
90 f(fd)
91 switch fd.Kind() {
Damien Neile475eaa2019-01-26 14:24:59 -080092 case protoreflect.MessageKind, protoreflect.GroupKind:
Joe Tsai378c1322019-04-25 23:48:08 -070093 if fd.IsList() {
Damien Neile475eaa2019-01-26 14:24:59 -080094 for i, list := 0, value.List(); i < list.Len(); i++ {
95 visitFields(list.Get(i).Message(), f)
96 }
97 } else {
98 visitFields(value.Message(), f)
99 }
100 }
101 return true
102 })
103}
Damien Neil82a03062019-05-08 07:52:49 -0700104
105func TestWeakInit(t *testing.T) {
106 file := testpb.File_test_test_proto
107 fd := file.Messages().ByName("TestWeak").Fields().ByName("weak_message")
108 if want, got := fd.IsWeak(), true; got != want {
109 t.Errorf("field %v: IsWeak() = %v, want %v", fd.FullName(), want, got)
110 }
111 if want, got := fd.Message().IsPlaceholder(), false; got != want {
112 t.Errorf("field %v: Message.IsPlaceholder() = %v, want %v", fd.FullName(), want, got)
113 }
114 if fd.Message().Fields().Len() == 0 {
115 t.Errorf("field %v: Message().Fields().Len() == 0, want >0", fd.FullName())
116 }
117}