blob: 08930a2b832ba1b94aa566983b69ae77cff1128d [file] [log] [blame]
Joe Tsaibfda0142018-08-10 13:58:07 -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
Joe Tsaid8881392019-06-06 13:01:53 -07005package filedesc_test
Joe Tsaibfda0142018-08-10 13:58:07 -07006
7import (
Joe Tsai17764982018-08-24 03:03:21 -07008 "fmt"
Joe Tsaibfda0142018-08-10 13:58:07 -07009 "reflect"
Joe Tsaidd00a272018-09-13 12:50:58 -070010 "regexp"
Joe Tsaibfda0142018-08-10 13:58:07 -070011 "strconv"
12 "strings"
Joe Tsaibfda0142018-08-10 13:58:07 -070013 "testing"
14
Joe Tsaiac31a352019-05-13 14:32:56 -070015 "github.com/google/go-cmp/cmp"
Damien Neile89e6242019-05-13 23:55:40 -070016 detrand "google.golang.org/protobuf/internal/detrand"
Joe Tsaid8881392019-06-06 13:01:53 -070017 "google.golang.org/protobuf/internal/filedesc"
Joe Tsaid8881392019-06-06 13:01:53 -070018 "google.golang.org/protobuf/proto"
Damien Neile89e6242019-05-13 23:55:40 -070019 pdesc "google.golang.org/protobuf/reflect/protodesc"
20 pref "google.golang.org/protobuf/reflect/protoreflect"
Joe Tsaie1f8d502018-11-26 18:55:29 -080021
Joe Tsaia95b29f2019-05-16 12:47:20 -070022 "google.golang.org/protobuf/types/descriptorpb"
Joe Tsaibfda0142018-08-10 13:58:07 -070023)
24
Joe Tsai05d60cd2018-12-06 16:44:24 -080025func init() {
26 // Disable detrand to enable direct comparisons on outputs.
27 detrand.Disable()
28}
29
Joe Tsaie1f8d502018-11-26 18:55:29 -080030// TODO: Test protodesc.NewFile with imported files.
Joe Tsai23ddbd12018-08-26 22:48:17 -070031
Joe Tsaibfda0142018-08-10 13:58:07 -070032func TestFile(t *testing.T) {
Joe Tsaid8881392019-06-06 13:01:53 -070033 f1 := &descriptorpb.FileDescriptorProto{
Damien Neila8a2cea2019-07-10 16:17:16 -070034 Syntax: proto.String("proto2"),
35 Name: proto.String("path/to/file.proto"),
36 Package: proto.String("test"),
37 Options: &descriptorpb.FileOptions{Deprecated: proto.Bool(true)},
Joe Tsaie1f8d502018-11-26 18:55:29 -080038 MessageType: []*descriptorpb.DescriptorProto{{
Damien Neila8a2cea2019-07-10 16:17:16 -070039 Name: proto.String("A"),
Joe Tsaie1f8d502018-11-26 18:55:29 -080040 Options: &descriptorpb.MessageOptions{
Damien Neila8a2cea2019-07-10 16:17:16 -070041 Deprecated: proto.Bool(true),
Damien Neil204f1c02018-10-23 15:03:38 -070042 },
Joe Tsai23ddbd12018-08-26 22:48:17 -070043 }, {
Damien Neila8a2cea2019-07-10 16:17:16 -070044 Name: proto.String("B"),
Joe Tsaie1f8d502018-11-26 18:55:29 -080045 Field: []*descriptorpb.FieldDescriptorProto{{
Damien Neila8a2cea2019-07-10 16:17:16 -070046 Name: proto.String("field_one"),
47 Number: proto.Int32(1),
Joe Tsaie1f8d502018-11-26 18:55:29 -080048 Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
49 Type: descriptorpb.FieldDescriptorProto_Type(pref.StringKind).Enum(),
Damien Neila8a2cea2019-07-10 16:17:16 -070050 DefaultValue: proto.String("hello, \"world!\"\n"),
51 OneofIndex: proto.Int32(0),
Joe Tsai23ddbd12018-08-26 22:48:17 -070052 }, {
Damien Neila8a2cea2019-07-10 16:17:16 -070053 Name: proto.String("field_two"),
54 JsonName: proto.String("Field2"),
55 Number: proto.Int32(2),
Joe Tsaie1f8d502018-11-26 18:55:29 -080056 Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
57 Type: descriptorpb.FieldDescriptorProto_Type(pref.EnumKind).Enum(),
Damien Neila8a2cea2019-07-10 16:17:16 -070058 DefaultValue: proto.String("BAR"),
59 TypeName: proto.String(".test.E1"),
60 OneofIndex: proto.Int32(1),
Joe Tsai23ddbd12018-08-26 22:48:17 -070061 }, {
Damien Neila8a2cea2019-07-10 16:17:16 -070062 Name: proto.String("field_three"),
63 Number: proto.Int32(3),
Joe Tsaie1f8d502018-11-26 18:55:29 -080064 Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
65 Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
Damien Neila8a2cea2019-07-10 16:17:16 -070066 TypeName: proto.String(".test.C"),
67 OneofIndex: proto.Int32(1),
Joe Tsai23ddbd12018-08-26 22:48:17 -070068 }, {
Damien Neila8a2cea2019-07-10 16:17:16 -070069 Name: proto.String("field_four"),
70 JsonName: proto.String("Field4"),
71 Number: proto.Int32(4),
Joe Tsaie1f8d502018-11-26 18:55:29 -080072 Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
73 Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
Damien Neila8a2cea2019-07-10 16:17:16 -070074 TypeName: proto.String(".test.B.FieldFourEntry"),
Joe Tsai23ddbd12018-08-26 22:48:17 -070075 }, {
Damien Neila8a2cea2019-07-10 16:17:16 -070076 Name: proto.String("field_five"),
77 Number: proto.Int32(5),
Joe Tsaie1f8d502018-11-26 18:55:29 -080078 Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
79 Type: descriptorpb.FieldDescriptorProto_Type(pref.Int32Kind).Enum(),
Damien Neila8a2cea2019-07-10 16:17:16 -070080 Options: &descriptorpb.FieldOptions{Packed: proto.Bool(true)},
Joe Tsai23ddbd12018-08-26 22:48:17 -070081 }, {
Damien Neila8a2cea2019-07-10 16:17:16 -070082 Name: proto.String("field_six"),
83 Number: proto.Int32(6),
Joe Tsaie1f8d502018-11-26 18:55:29 -080084 Label: descriptorpb.FieldDescriptorProto_Label(pref.Required).Enum(),
85 Type: descriptorpb.FieldDescriptorProto_Type(pref.BytesKind).Enum(),
Joe Tsai23ddbd12018-08-26 22:48:17 -070086 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -080087 OneofDecl: []*descriptorpb.OneofDescriptorProto{
Damien Neil204f1c02018-10-23 15:03:38 -070088 {
Damien Neila8a2cea2019-07-10 16:17:16 -070089 Name: proto.String("O1"),
Joe Tsaie1f8d502018-11-26 18:55:29 -080090 Options: &descriptorpb.OneofOptions{
91 UninterpretedOption: []*descriptorpb.UninterpretedOption{
Damien Neil204f1c02018-10-23 15:03:38 -070092 {StringValue: []byte("option")},
93 },
94 },
95 },
Damien Neila8a2cea2019-07-10 16:17:16 -070096 {Name: proto.String("O2")},
Joe Tsai23ddbd12018-08-26 22:48:17 -070097 },
Joe Tsaibce82b82018-12-06 09:39:03 -080098 ReservedName: []string{"fizz", "buzz"},
99 ReservedRange: []*descriptorpb.DescriptorProto_ReservedRange{
Damien Neila8a2cea2019-07-10 16:17:16 -0700100 {Start: proto.Int32(100), End: proto.Int32(200)},
101 {Start: proto.Int32(300), End: proto.Int32(301)},
Joe Tsaibce82b82018-12-06 09:39:03 -0800102 },
Joe Tsaie1f8d502018-11-26 18:55:29 -0800103 ExtensionRange: []*descriptorpb.DescriptorProto_ExtensionRange{
Damien Neila8a2cea2019-07-10 16:17:16 -0700104 {Start: proto.Int32(1000), End: proto.Int32(2000)},
105 {Start: proto.Int32(3000), End: proto.Int32(3001), Options: new(descriptorpb.ExtensionRangeOptions)},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700106 },
Joe Tsai15076352019-07-02 15:19:08 -0700107 NestedType: []*descriptorpb.DescriptorProto{{
Damien Neila8a2cea2019-07-10 16:17:16 -0700108 Name: proto.String("FieldFourEntry"),
Joe Tsai15076352019-07-02 15:19:08 -0700109 Field: []*descriptorpb.FieldDescriptorProto{{
Damien Neila8a2cea2019-07-10 16:17:16 -0700110 Name: proto.String("key"),
111 Number: proto.Int32(1),
Joe Tsai15076352019-07-02 15:19:08 -0700112 Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
113 Type: descriptorpb.FieldDescriptorProto_Type(pref.StringKind).Enum(),
114 }, {
Damien Neila8a2cea2019-07-10 16:17:16 -0700115 Name: proto.String("value"),
116 Number: proto.Int32(2),
Joe Tsai15076352019-07-02 15:19:08 -0700117 Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
118 Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
Damien Neila8a2cea2019-07-10 16:17:16 -0700119 TypeName: proto.String(".test.B"),
Joe Tsai15076352019-07-02 15:19:08 -0700120 }},
121 Options: &descriptorpb.MessageOptions{
Damien Neila8a2cea2019-07-10 16:17:16 -0700122 MapEntry: proto.Bool(true),
Joe Tsai15076352019-07-02 15:19:08 -0700123 },
124 }},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700125 }, {
Damien Neila8a2cea2019-07-10 16:17:16 -0700126 Name: proto.String("C"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800127 NestedType: []*descriptorpb.DescriptorProto{{
Damien Neila8a2cea2019-07-10 16:17:16 -0700128 Name: proto.String("A"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800129 Field: []*descriptorpb.FieldDescriptorProto{{
Damien Neila8a2cea2019-07-10 16:17:16 -0700130 Name: proto.String("F"),
131 Number: proto.Int32(1),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800132 Label: descriptorpb.FieldDescriptorProto_Label(pref.Required).Enum(),
133 Type: descriptorpb.FieldDescriptorProto_Type(pref.BytesKind).Enum(),
Damien Neila8a2cea2019-07-10 16:17:16 -0700134 DefaultValue: proto.String(`dead\276\357`),
Joe Tsai23ddbd12018-08-26 22:48:17 -0700135 }},
136 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800137 EnumType: []*descriptorpb.EnumDescriptorProto{{
Damien Neila8a2cea2019-07-10 16:17:16 -0700138 Name: proto.String("E1"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800139 Value: []*descriptorpb.EnumValueDescriptorProto{
Damien Neila8a2cea2019-07-10 16:17:16 -0700140 {Name: proto.String("FOO"), Number: proto.Int32(0)},
141 {Name: proto.String("BAR"), Number: proto.Int32(1)},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700142 },
143 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800144 Extension: []*descriptorpb.FieldDescriptorProto{{
Damien Neila8a2cea2019-07-10 16:17:16 -0700145 Name: proto.String("X"),
146 Number: proto.Int32(1000),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800147 Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
148 Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
Damien Neila8a2cea2019-07-10 16:17:16 -0700149 TypeName: proto.String(".test.C"),
150 Extendee: proto.String(".test.B"),
Joe Tsai23ddbd12018-08-26 22:48:17 -0700151 }},
152 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800153 EnumType: []*descriptorpb.EnumDescriptorProto{{
Damien Neila8a2cea2019-07-10 16:17:16 -0700154 Name: proto.String("E1"),
155 Options: &descriptorpb.EnumOptions{Deprecated: proto.Bool(true)},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800156 Value: []*descriptorpb.EnumValueDescriptorProto{
Damien Neil204f1c02018-10-23 15:03:38 -0700157 {
Damien Neila8a2cea2019-07-10 16:17:16 -0700158 Name: proto.String("FOO"),
159 Number: proto.Int32(0),
160 Options: &descriptorpb.EnumValueOptions{Deprecated: proto.Bool(true)},
Damien Neil204f1c02018-10-23 15:03:38 -0700161 },
Damien Neila8a2cea2019-07-10 16:17:16 -0700162 {Name: proto.String("BAR"), Number: proto.Int32(1)},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700163 },
Joe Tsaibce82b82018-12-06 09:39:03 -0800164 ReservedName: []string{"FIZZ", "BUZZ"},
165 ReservedRange: []*descriptorpb.EnumDescriptorProto_EnumReservedRange{
Damien Neila8a2cea2019-07-10 16:17:16 -0700166 {Start: proto.Int32(10), End: proto.Int32(19)},
167 {Start: proto.Int32(30), End: proto.Int32(30)},
Joe Tsaibce82b82018-12-06 09:39:03 -0800168 },
Joe Tsai23ddbd12018-08-26 22:48:17 -0700169 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800170 Extension: []*descriptorpb.FieldDescriptorProto{{
Damien Neila8a2cea2019-07-10 16:17:16 -0700171 Name: proto.String("X"),
172 Number: proto.Int32(1000),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800173 Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
Joe Tsai15076352019-07-02 15:19:08 -0700174 Type: descriptorpb.FieldDescriptorProto_Type(pref.EnumKind).Enum(),
Damien Neila8a2cea2019-07-10 16:17:16 -0700175 Options: &descriptorpb.FieldOptions{Packed: proto.Bool(true)},
176 TypeName: proto.String(".test.E1"),
177 Extendee: proto.String(".test.B"),
Joe Tsai23ddbd12018-08-26 22:48:17 -0700178 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800179 Service: []*descriptorpb.ServiceDescriptorProto{{
Damien Neila8a2cea2019-07-10 16:17:16 -0700180 Name: proto.String("S"),
181 Options: &descriptorpb.ServiceOptions{Deprecated: proto.Bool(true)},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800182 Method: []*descriptorpb.MethodDescriptorProto{{
Damien Neila8a2cea2019-07-10 16:17:16 -0700183 Name: proto.String("M"),
184 InputType: proto.String(".test.A"),
185 OutputType: proto.String(".test.C.A"),
186 ClientStreaming: proto.Bool(true),
187 ServerStreaming: proto.Bool(true),
188 Options: &descriptorpb.MethodOptions{Deprecated: proto.Bool(true)},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700189 }},
190 }},
191 }
Joe Tsaid8881392019-06-06 13:01:53 -0700192 fd1, err := pdesc.NewFile(f1, nil)
Joe Tsai23ddbd12018-08-26 22:48:17 -0700193 if err != nil {
Joe Tsaie1f8d502018-11-26 18:55:29 -0800194 t.Fatalf("protodesc.NewFile() error: %v", err)
Joe Tsai23ddbd12018-08-26 22:48:17 -0700195 }
196
Joe Tsaid8881392019-06-06 13:01:53 -0700197 b, err := proto.Marshal(f1)
198 if err != nil {
199 t.Fatalf("proto.Marshal() error: %v", err)
200 }
Joe Tsai52ec1752019-08-05 15:49:29 -0700201 fd2 := filedesc.Builder{RawDescriptor: b}.Build().File
Joe Tsaid8881392019-06-06 13:01:53 -0700202
Joe Tsai23ddbd12018-08-26 22:48:17 -0700203 tests := []struct {
204 name string
205 desc pref.FileDescriptor
206 }{
Joe Tsaid8881392019-06-06 13:01:53 -0700207 {"protodesc.NewFile", fd1},
Joe Tsai52ec1752019-08-05 15:49:29 -0700208 {"filedesc.Builder.Build", fd2},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700209 }
210 for _, tt := range tests {
Joe Tsai17764982018-08-24 03:03:21 -0700211 tt := tt
Joe Tsai23ddbd12018-08-26 22:48:17 -0700212 t.Run(tt.name, func(t *testing.T) {
Joe Tsai17764982018-08-24 03:03:21 -0700213 // Run sub-tests in parallel to induce potential races.
214 for i := 0; i < 2; i++ {
215 t.Run("Accessors", func(t *testing.T) { t.Parallel(); testFileAccessors(t, tt.desc) })
Joe Tsaidd00a272018-09-13 12:50:58 -0700216 t.Run("Format", func(t *testing.T) { t.Parallel(); testFileFormat(t, tt.desc) })
Joe Tsai17764982018-08-24 03:03:21 -0700217 }
Joe Tsai23ddbd12018-08-26 22:48:17 -0700218 })
219 }
220}
221
222func testFileAccessors(t *testing.T, fd pref.FileDescriptor) {
Joe Tsaibfda0142018-08-10 13:58:07 -0700223 // Represent the descriptor as a map where each key is an accessor method
224 // and the value is either the wanted tail value or another accessor map.
225 type M = map[string]interface{}
226 want := M{
227 "Parent": nil,
Damien Neil3de06c02018-09-07 09:39:44 -0700228 "Index": 0,
Joe Tsaibfda0142018-08-10 13:58:07 -0700229 "Syntax": pref.Proto2,
230 "Name": pref.Name("test"),
231 "FullName": pref.FullName("test"),
232 "Path": "path/to/file.proto",
233 "Package": pref.FullName("test"),
234 "IsPlaceholder": false,
Damien Neila8a2cea2019-07-10 16:17:16 -0700235 "Options": &descriptorpb.FileOptions{Deprecated: proto.Bool(true)},
Joe Tsaibfda0142018-08-10 13:58:07 -0700236 "Messages": M{
237 "Len": 3,
238 "Get:0": M{
239 "Parent": M{"FullName": pref.FullName("test")},
Damien Neil3de06c02018-09-07 09:39:44 -0700240 "Index": 0,
Joe Tsaibfda0142018-08-10 13:58:07 -0700241 "Syntax": pref.Proto2,
242 "Name": pref.Name("A"),
243 "FullName": pref.FullName("test.A"),
244 "IsPlaceholder": false,
Joe Tsai15076352019-07-02 15:19:08 -0700245 "IsMapEntry": false,
Joe Tsaie1f8d502018-11-26 18:55:29 -0800246 "Options": &descriptorpb.MessageOptions{
Damien Neila8a2cea2019-07-10 16:17:16 -0700247 Deprecated: proto.Bool(true),
Damien Neil204f1c02018-10-23 15:03:38 -0700248 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700249 "Oneofs": M{"Len": 0},
250 "RequiredNumbers": M{"Len": 0},
251 "ExtensionRanges": M{"Len": 0},
252 "Messages": M{"Len": 0},
253 "Enums": M{"Len": 0},
254 "Extensions": M{"Len": 0},
255 },
256 "ByName:B": M{
Damien Neil3de06c02018-09-07 09:39:44 -0700257 "Name": pref.Name("B"),
258 "Index": 1,
Joe Tsaibfda0142018-08-10 13:58:07 -0700259 "Fields": M{
260 "Len": 6,
261 "ByJSONName:field_one": nil,
262 "ByJSONName:fieldOne": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700263 "Name": pref.Name("field_one"),
264 "Index": 0,
265 "JSONName": "fieldOne",
266 "Default": "hello, \"world!\"\n",
267 "ContainingOneof": M{"Name": pref.Name("O1"), "IsPlaceholder": false},
268 "ContainingMessage": M{"FullName": pref.FullName("test.B")},
Joe Tsaibfda0142018-08-10 13:58:07 -0700269 },
270 "ByJSONName:fieldTwo": nil,
271 "ByJSONName:Field2": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700272 "Name": pref.Name("field_two"),
273 "Index": 1,
274 "HasJSONName": true,
275 "JSONName": "Field2",
276 "Default": pref.EnumNumber(1),
277 "ContainingOneof": M{"Name": pref.Name("O2"), "IsPlaceholder": false},
Joe Tsaibfda0142018-08-10 13:58:07 -0700278 },
279 "ByName:fieldThree": nil,
280 "ByName:field_three": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700281 "IsExtension": false,
282 "IsMap": false,
283 "MapKey": nil,
284 "MapValue": nil,
285 "Message": M{"FullName": pref.FullName("test.C"), "IsPlaceholder": false},
286 "ContainingOneof": M{"Name": pref.Name("O2"), "IsPlaceholder": false},
287 "ContainingMessage": M{"FullName": pref.FullName("test.B")},
Joe Tsaibfda0142018-08-10 13:58:07 -0700288 },
289 "ByNumber:12": nil,
290 "ByNumber:4": M{
291 "Cardinality": pref.Repeated,
Joe Tsaiac31a352019-05-13 14:32:56 -0700292 "IsExtension": false,
293 "IsList": false,
Joe Tsaibfda0142018-08-10 13:58:07 -0700294 "IsMap": true,
Joe Tsaiac31a352019-05-13 14:32:56 -0700295 "MapKey": M{"Kind": pref.StringKind},
296 "MapValue": M{"Kind": pref.MessageKind, "Message": M{"FullName": pref.FullName("test.B")}},
Joe Tsaibfda0142018-08-10 13:58:07 -0700297 "Default": nil,
Joe Tsai15076352019-07-02 15:19:08 -0700298 "Message": M{"FullName": pref.FullName("test.B.FieldFourEntry"), "IsPlaceholder": false},
Joe Tsaibfda0142018-08-10 13:58:07 -0700299 },
300 "ByNumber:5": M{
301 "Cardinality": pref.Repeated,
302 "Kind": pref.Int32Kind,
303 "IsPacked": true,
Joe Tsaiac31a352019-05-13 14:32:56 -0700304 "IsList": true,
305 "IsMap": false,
Joe Tsai851185d2019-07-01 13:45:52 -0700306 "Default": nil,
Joe Tsaibfda0142018-08-10 13:58:07 -0700307 },
308 "ByNumber:6": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700309 "Cardinality": pref.Required,
310 "Default": []byte(nil),
311 "ContainingOneof": nil,
Joe Tsaibfda0142018-08-10 13:58:07 -0700312 },
313 },
314 "Oneofs": M{
315 "Len": 2,
316 "ByName:O0": nil,
317 "ByName:O1": M{
318 "FullName": pref.FullName("test.B.O1"),
Damien Neil3de06c02018-09-07 09:39:44 -0700319 "Index": 0,
Joe Tsaie1f8d502018-11-26 18:55:29 -0800320 "Options": &descriptorpb.OneofOptions{
321 UninterpretedOption: []*descriptorpb.UninterpretedOption{
Damien Neil204f1c02018-10-23 15:03:38 -0700322 {StringValue: []byte("option")},
323 },
324 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700325 "Fields": M{
326 "Len": 1,
327 "Get:0": M{"FullName": pref.FullName("test.B.field_one")},
328 },
329 },
330 "Get:1": M{
331 "FullName": pref.FullName("test.B.O2"),
Damien Neil3de06c02018-09-07 09:39:44 -0700332 "Index": 1,
Joe Tsaibfda0142018-08-10 13:58:07 -0700333 "Fields": M{
334 "Len": 2,
335 "ByName:field_two": M{"Name": pref.Name("field_two")},
336 "Get:1": M{"Name": pref.Name("field_three")},
337 },
338 },
339 },
Joe Tsaibce82b82018-12-06 09:39:03 -0800340 "ReservedNames": M{
341 "Len": 2,
342 "Get:0": pref.Name("fizz"),
343 "Has:buzz": true,
344 "Has:noexist": false,
345 },
346 "ReservedRanges": M{
347 "Len": 2,
348 "Get:0": [2]pref.FieldNumber{100, 200},
349 "Has:99": false,
350 "Has:100": true,
351 "Has:150": true,
352 "Has:199": true,
353 "Has:200": false,
354 "Has:300": true,
355 "Has:301": false,
356 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700357 "RequiredNumbers": M{
358 "Len": 1,
359 "Get:0": pref.FieldNumber(6),
360 "Has:1": false,
361 "Has:6": true,
362 },
363 "ExtensionRanges": M{
Joe Tsai17764982018-08-24 03:03:21 -0700364 "Len": 2,
Joe Tsaibfda0142018-08-10 13:58:07 -0700365 "Get:0": [2]pref.FieldNumber{1000, 2000},
366 "Has:999": false,
367 "Has:1000": true,
368 "Has:1500": true,
369 "Has:1999": true,
370 "Has:2000": false,
Joe Tsai17764982018-08-24 03:03:21 -0700371 "Has:3000": true,
Joe Tsaibce82b82018-12-06 09:39:03 -0800372 "Has:3001": false,
Joe Tsaibfda0142018-08-10 13:58:07 -0700373 },
Joe Tsai381f04c2018-12-06 12:10:41 -0800374 "ExtensionRangeOptions:0": (*descriptorpb.ExtensionRangeOptions)(nil),
375 "ExtensionRangeOptions:1": new(descriptorpb.ExtensionRangeOptions),
Joe Tsai15076352019-07-02 15:19:08 -0700376 "Messages": M{
377 "Get:0": M{
378 "Fields": M{
379 "Len": 2,
380 "ByNumber:1": M{
381 "Parent": M{"FullName": pref.FullName("test.B.FieldFourEntry")},
382 "Index": 0,
383 "Name": pref.Name("key"),
384 "FullName": pref.FullName("test.B.FieldFourEntry.key"),
385 "Number": pref.FieldNumber(1),
386 "Cardinality": pref.Optional,
387 "Kind": pref.StringKind,
388 "Options": (*descriptorpb.FieldOptions)(nil),
389 "HasJSONName": false,
390 "JSONName": "key",
391 "IsPacked": false,
392 "IsList": false,
393 "IsMap": false,
394 "IsExtension": false,
395 "IsWeak": false,
396 "Default": "",
397 "ContainingOneof": nil,
398 "ContainingMessage": M{"FullName": pref.FullName("test.B.FieldFourEntry")},
399 "Message": nil,
400 "Enum": nil,
401 },
402 "ByNumber:2": M{
403 "Parent": M{"FullName": pref.FullName("test.B.FieldFourEntry")},
404 "Index": 1,
405 "Name": pref.Name("value"),
406 "FullName": pref.FullName("test.B.FieldFourEntry.value"),
407 "Number": pref.FieldNumber(2),
408 "Cardinality": pref.Optional,
409 "Kind": pref.MessageKind,
410 "JSONName": "value",
411 "IsPacked": false,
412 "IsList": false,
413 "IsMap": false,
414 "IsExtension": false,
415 "IsWeak": false,
416 "Default": nil,
417 "ContainingOneof": nil,
418 "ContainingMessage": M{"FullName": pref.FullName("test.B.FieldFourEntry")},
419 "Message": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
420 "Enum": nil,
421 },
422 "ByNumber:3": nil,
423 },
424 },
425 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700426 },
427 "Get:2": M{
Damien Neil3de06c02018-09-07 09:39:44 -0700428 "Name": pref.Name("C"),
429 "Index": 2,
Joe Tsaibfda0142018-08-10 13:58:07 -0700430 "Messages": M{
431 "Len": 1,
432 "Get:0": M{"FullName": pref.FullName("test.C.A")},
433 },
434 "Enums": M{
435 "Len": 1,
436 "Get:0": M{"FullName": pref.FullName("test.C.E1")},
437 },
438 "Extensions": M{
439 "Len": 1,
440 "Get:0": M{"FullName": pref.FullName("test.C.X")},
441 },
442 },
443 },
444 "Enums": M{
445 "Len": 1,
446 "Get:0": M{
Damien Neil204f1c02018-10-23 15:03:38 -0700447 "Name": pref.Name("E1"),
Damien Neila8a2cea2019-07-10 16:17:16 -0700448 "Options": &descriptorpb.EnumOptions{Deprecated: proto.Bool(true)},
Joe Tsaibfda0142018-08-10 13:58:07 -0700449 "Values": M{
450 "Len": 2,
451 "ByName:Foo": nil,
Damien Neil204f1c02018-10-23 15:03:38 -0700452 "ByName:FOO": M{
453 "FullName": pref.FullName("test.FOO"),
Damien Neila8a2cea2019-07-10 16:17:16 -0700454 "Options": &descriptorpb.EnumValueOptions{Deprecated: proto.Bool(true)},
Damien Neil204f1c02018-10-23 15:03:38 -0700455 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700456 "ByNumber:2": nil,
457 "ByNumber:1": M{"FullName": pref.FullName("test.BAR")},
458 },
Joe Tsaibce82b82018-12-06 09:39:03 -0800459 "ReservedNames": M{
460 "Len": 2,
461 "Get:0": pref.Name("FIZZ"),
462 "Has:BUZZ": true,
463 "Has:NOEXIST": false,
464 },
465 "ReservedRanges": M{
466 "Len": 2,
467 "Get:0": [2]pref.EnumNumber{10, 19},
468 "Has:9": false,
469 "Has:10": true,
470 "Has:15": true,
471 "Has:19": true,
472 "Has:20": false,
473 "Has:30": true,
474 "Has:31": false,
475 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700476 },
477 },
478 "Extensions": M{
479 "Len": 1,
480 "ByName:X": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700481 "Name": pref.Name("X"),
482 "Number": pref.FieldNumber(1000),
483 "Cardinality": pref.Repeated,
Joe Tsai15076352019-07-02 15:19:08 -0700484 "Kind": pref.EnumKind,
Joe Tsaiac31a352019-05-13 14:32:56 -0700485 "IsExtension": true,
Joe Tsaid8881392019-06-06 13:01:53 -0700486 "IsPacked": true,
Joe Tsaiac31a352019-05-13 14:32:56 -0700487 "IsList": true,
488 "IsMap": false,
489 "MapKey": nil,
490 "MapValue": nil,
491 "ContainingOneof": nil,
492 "ContainingMessage": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
Joe Tsai15076352019-07-02 15:19:08 -0700493 "Enum": M{"FullName": pref.FullName("test.E1"), "IsPlaceholder": false},
Damien Neila8a2cea2019-07-10 16:17:16 -0700494 "Options": &descriptorpb.FieldOptions{Packed: proto.Bool(true)},
Joe Tsaibfda0142018-08-10 13:58:07 -0700495 },
496 },
497 "Services": M{
498 "Len": 1,
499 "ByName:s": nil,
500 "ByName:S": M{
501 "Parent": M{"FullName": pref.FullName("test")},
502 "Name": pref.Name("S"),
503 "FullName": pref.FullName("test.S"),
Damien Neila8a2cea2019-07-10 16:17:16 -0700504 "Options": &descriptorpb.ServiceOptions{Deprecated: proto.Bool(true)},
Joe Tsaibfda0142018-08-10 13:58:07 -0700505 "Methods": M{
506 "Len": 1,
507 "Get:0": M{
508 "Parent": M{"FullName": pref.FullName("test.S")},
509 "Name": pref.Name("M"),
510 "FullName": pref.FullName("test.S.M"),
Joe Tsaid24bc722019-04-15 23:39:09 -0700511 "Input": M{"FullName": pref.FullName("test.A"), "IsPlaceholder": false},
512 "Output": M{"FullName": pref.FullName("test.C.A"), "IsPlaceholder": false},
Joe Tsaibfda0142018-08-10 13:58:07 -0700513 "IsStreamingClient": true,
514 "IsStreamingServer": true,
Damien Neila8a2cea2019-07-10 16:17:16 -0700515 "Options": &descriptorpb.MethodOptions{Deprecated: proto.Bool(true)},
Joe Tsaibfda0142018-08-10 13:58:07 -0700516 },
517 },
518 },
519 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700520 }
Joe Tsai23ddbd12018-08-26 22:48:17 -0700521 checkAccessors(t, "", reflect.ValueOf(fd), want)
Joe Tsaibfda0142018-08-10 13:58:07 -0700522}
Joe Tsaibfda0142018-08-10 13:58:07 -0700523func checkAccessors(t *testing.T, p string, rv reflect.Value, want map[string]interface{}) {
Joe Tsaie1f8d502018-11-26 18:55:29 -0800524 p0 := p
525 defer func() {
526 if ex := recover(); ex != nil {
527 t.Errorf("panic at %v: %v", p, ex)
528 }
529 }()
530
Joe Tsaibfda0142018-08-10 13:58:07 -0700531 if rv.Interface() == nil {
532 t.Errorf("%v is nil, want non-nil", p)
533 return
534 }
535 for s, v := range want {
536 // Call the accessor method.
Joe Tsaie1f8d502018-11-26 18:55:29 -0800537 p = p0 + "." + s
Joe Tsaibfda0142018-08-10 13:58:07 -0700538 var rets []reflect.Value
539 if i := strings.IndexByte(s, ':'); i >= 0 {
540 // Accessor method takes in a single argument, which is encoded
541 // after the accessor name, separated by a ':' delimiter.
542 fnc := rv.MethodByName(s[:i])
543 arg := reflect.New(fnc.Type().In(0)).Elem()
544 s = s[i+len(":"):]
545 switch arg.Kind() {
546 case reflect.String:
547 arg.SetString(s)
548 case reflect.Int32, reflect.Int:
549 n, _ := strconv.ParseInt(s, 0, 64)
550 arg.SetInt(n)
551 }
552 rets = fnc.Call([]reflect.Value{arg})
553 } else {
554 rets = rv.MethodByName(s).Call(nil)
555 }
556
557 // Check that (val, ok) pattern is internally consistent.
558 if len(rets) == 2 {
559 if rets[0].IsNil() && rets[1].Bool() {
560 t.Errorf("%v = (nil, true), want (nil, false)", p)
561 }
562 if !rets[0].IsNil() && !rets[1].Bool() {
563 t.Errorf("%v = (non-nil, false), want (non-nil, true)", p)
564 }
565 }
566
567 // Check that the accessor output matches.
568 if want, ok := v.(map[string]interface{}); ok {
569 checkAccessors(t, p, rets[0], want)
Damien Neil204f1c02018-10-23 15:03:38 -0700570 continue
571 }
572
573 got := rets[0].Interface()
574 if pv, ok := got.(pref.Value); ok {
575 got = pv.Interface()
576 }
577
578 // Compare with proto.Equal if possible.
Joe Tsaid8881392019-06-06 13:01:53 -0700579 gotMsg, gotMsgOK := got.(proto.Message)
580 wantMsg, wantMsgOK := v.(proto.Message)
Damien Neil204f1c02018-10-23 15:03:38 -0700581 if gotMsgOK && wantMsgOK {
Joe Tsaid8881392019-06-06 13:01:53 -0700582 gotNil := reflect.ValueOf(gotMsg).IsNil()
583 wantNil := reflect.ValueOf(wantMsg).IsNil()
584 switch {
585 case !gotNil && wantNil:
586 t.Errorf("%v = non-nil, want nil", p)
587 case gotNil && !wantNil:
588 t.Errorf("%v = nil, want non-nil", p)
589 case !proto.Equal(gotMsg, wantMsg):
590 t.Errorf("%v = %v, want %v", p, gotMsg, wantMsg)
Joe Tsaibfda0142018-08-10 13:58:07 -0700591 }
Damien Neil204f1c02018-10-23 15:03:38 -0700592 continue
593 }
594
595 if want := v; !reflect.DeepEqual(got, want) {
Joe Tsai381f04c2018-12-06 12:10:41 -0800596 t.Errorf("%v = %T(%v), want %T(%v)", p, got, got, want, want)
Joe Tsaibfda0142018-08-10 13:58:07 -0700597 }
598 }
599}
600
Joe Tsaidd00a272018-09-13 12:50:58 -0700601func testFileFormat(t *testing.T, fd pref.FileDescriptor) {
Joe Tsai17764982018-08-24 03:03:21 -0700602 const want = `FileDescriptor{
603 Syntax: proto2
604 Path: "path/to/file.proto"
605 Package: test
606 Messages: [{
Joe Tsai15076352019-07-02 15:19:08 -0700607 Name: A
Joe Tsai17764982018-08-24 03:03:21 -0700608 }, {
609 Name: B
610 Fields: [{
611 Name: field_one
612 Number: 1
613 Cardinality: optional
614 Kind: string
615 JSONName: "fieldOne"
Damien Neile6fa22a2018-09-12 15:15:40 -0700616 HasDefault: true
Joe Tsai1dab2cb2018-09-28 13:39:07 -0700617 Default: "hello, \"world!\"\n"
Joe Tsaid24bc722019-04-15 23:39:09 -0700618 Oneof: O1
Joe Tsai17764982018-08-24 03:03:21 -0700619 }, {
620 Name: field_two
621 Number: 2
622 Cardinality: optional
623 Kind: enum
Joe Tsaibce82b82018-12-06 09:39:03 -0800624 HasJSONName: true
Joe Tsai17764982018-08-24 03:03:21 -0700625 JSONName: "Field2"
Damien Neile6fa22a2018-09-12 15:15:40 -0700626 HasDefault: true
Joe Tsai17764982018-08-24 03:03:21 -0700627 Default: 1
Joe Tsaid24bc722019-04-15 23:39:09 -0700628 Oneof: O2
629 Enum: test.E1
Joe Tsai17764982018-08-24 03:03:21 -0700630 }, {
631 Name: field_three
632 Number: 3
633 Cardinality: optional
634 Kind: message
635 JSONName: "fieldThree"
Joe Tsaid24bc722019-04-15 23:39:09 -0700636 Oneof: O2
637 Message: test.C
Joe Tsai17764982018-08-24 03:03:21 -0700638 }, {
639 Name: field_four
640 Number: 4
641 Cardinality: repeated
642 Kind: message
Joe Tsaibce82b82018-12-06 09:39:03 -0800643 HasJSONName: true
Joe Tsai17764982018-08-24 03:03:21 -0700644 JSONName: "Field4"
645 IsMap: true
Joe Tsaiac31a352019-05-13 14:32:56 -0700646 MapKey: string
647 MapValue: test.B
Joe Tsai17764982018-08-24 03:03:21 -0700648 }, {
649 Name: field_five
650 Number: 5
651 Cardinality: repeated
652 Kind: int32
653 JSONName: "fieldFive"
654 IsPacked: true
Joe Tsaiac31a352019-05-13 14:32:56 -0700655 IsList: true
Joe Tsai17764982018-08-24 03:03:21 -0700656 }, {
657 Name: field_six
658 Number: 6
659 Cardinality: required
660 Kind: bytes
661 JSONName: "fieldSix"
662 }]
663 Oneofs: [{
664 Name: O1
665 Fields: [field_one]
666 }, {
667 Name: O2
668 Fields: [field_two, field_three]
669 }]
Joe Tsaibce82b82018-12-06 09:39:03 -0800670 ReservedNames: [fizz, buzz]
671 ReservedRanges: [100:200, 300]
Joe Tsai17764982018-08-24 03:03:21 -0700672 RequiredNumbers: [6]
673 ExtensionRanges: [1000:2000, 3000]
Joe Tsai15076352019-07-02 15:19:08 -0700674 Messages: [{
675 Name: FieldFourEntry
676 IsMapEntry: true
677 Fields: [{
678 Name: key
679 Number: 1
680 Cardinality: optional
681 Kind: string
682 JSONName: "key"
683 }, {
684 Name: value
685 Number: 2
686 Cardinality: optional
687 Kind: message
688 JSONName: "value"
689 Message: test.B
690 }]
691 }]
Joe Tsai17764982018-08-24 03:03:21 -0700692 }, {
693 Name: C
694 Messages: [{
695 Name: A
696 Fields: [{
697 Name: F
698 Number: 1
699 Cardinality: required
700 Kind: bytes
701 JSONName: "F"
Damien Neile6fa22a2018-09-12 15:15:40 -0700702 HasDefault: true
Joe Tsai17764982018-08-24 03:03:21 -0700703 Default: "dead\xbe\xef"
704 }]
705 RequiredNumbers: [1]
706 }]
707 Enums: [{
708 Name: E1
709 Values: [
710 {Name: FOO}
711 {Name: BAR, Number: 1}
712 ]
713 }]
714 Extensions: [{
Joe Tsaid24bc722019-04-15 23:39:09 -0700715 Name: X
716 Number: 1000
717 Cardinality: repeated
718 Kind: message
Joe Tsaid8881392019-06-06 13:01:53 -0700719 JSONName: "X"
Joe Tsaiac31a352019-05-13 14:32:56 -0700720 IsExtension: true
721 IsList: true
Joe Tsaid24bc722019-04-15 23:39:09 -0700722 Extendee: test.B
723 Message: test.C
Joe Tsai17764982018-08-24 03:03:21 -0700724 }]
725 }]
726 Enums: [{
727 Name: E1
728 Values: [
729 {Name: FOO}
730 {Name: BAR, Number: 1}
731 ]
Joe Tsaibce82b82018-12-06 09:39:03 -0800732 ReservedNames: [FIZZ, BUZZ]
733 ReservedRanges: [10:20, 30]
Joe Tsai17764982018-08-24 03:03:21 -0700734 }]
735 Extensions: [{
Joe Tsaid24bc722019-04-15 23:39:09 -0700736 Name: X
737 Number: 1000
738 Cardinality: repeated
Joe Tsai15076352019-07-02 15:19:08 -0700739 Kind: enum
Joe Tsaid8881392019-06-06 13:01:53 -0700740 JSONName: "X"
741 IsPacked: true
Joe Tsaiac31a352019-05-13 14:32:56 -0700742 IsExtension: true
743 IsList: true
Joe Tsaid24bc722019-04-15 23:39:09 -0700744 Extendee: test.B
Joe Tsai15076352019-07-02 15:19:08 -0700745 Enum: test.E1
Joe Tsai17764982018-08-24 03:03:21 -0700746 }]
747 Services: [{
748 Name: S
749 Methods: [{
750 Name: M
Joe Tsaid24bc722019-04-15 23:39:09 -0700751 Input: test.A
752 Output: test.C.A
Joe Tsai17764982018-08-24 03:03:21 -0700753 IsStreamingClient: true
754 IsStreamingServer: true
755 }]
756 }]
757}`
Joe Tsaidd00a272018-09-13 12:50:58 -0700758 tests := []struct{ fmt, want string }{{"%v", compactMultiFormat(want)}, {"%+v", want}}
759 for _, tt := range tests {
760 got := fmt.Sprintf(tt.fmt, fd)
Joe Tsaiac31a352019-05-13 14:32:56 -0700761 if diff := cmp.Diff(got, tt.want); diff != "" {
762 t.Errorf("fmt.Sprintf(%q, fd) mismatch (-got +want):\n%s", tt.fmt, diff)
Joe Tsaidd00a272018-09-13 12:50:58 -0700763 }
Joe Tsai17764982018-08-24 03:03:21 -0700764 }
765}
766
Joe Tsaidd00a272018-09-13 12:50:58 -0700767// compactMultiFormat returns the single line form of a multi line output.
768func compactMultiFormat(s string) string {
769 var b []byte
770 for _, s := range strings.Split(s, "\n") {
771 s = strings.TrimSpace(s)
772 s = regexp.MustCompile(": +").ReplaceAllString(s, ": ")
773 prevWord := len(b) > 0 && b[len(b)-1] != '[' && b[len(b)-1] != '{'
774 nextWord := len(s) > 0 && s[0] != ']' && s[0] != '}'
775 if prevWord && nextWord {
776 b = append(b, ", "...)
777 }
778 b = append(b, s...)
779 }
780 return string(b)
781}