blob: b6e0f7d1f14a7eb0c0baf8ebeac3a43c578b542e [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"
Damien Neile89e6242019-05-13 23:55:40 -070018 scalar "google.golang.org/protobuf/internal/scalar"
Joe Tsaid8881392019-06-06 13:01:53 -070019 "google.golang.org/protobuf/proto"
Damien Neile89e6242019-05-13 23:55:40 -070020 pdesc "google.golang.org/protobuf/reflect/protodesc"
21 pref "google.golang.org/protobuf/reflect/protoreflect"
Joe Tsaie1f8d502018-11-26 18:55:29 -080022
Joe Tsaia95b29f2019-05-16 12:47:20 -070023 "google.golang.org/protobuf/types/descriptorpb"
Joe Tsaibfda0142018-08-10 13:58:07 -070024)
25
Joe Tsai05d60cd2018-12-06 16:44:24 -080026func init() {
27 // Disable detrand to enable direct comparisons on outputs.
28 detrand.Disable()
29}
30
Joe Tsaie1f8d502018-11-26 18:55:29 -080031// TODO: Test protodesc.NewFile with imported files.
Joe Tsai23ddbd12018-08-26 22:48:17 -070032
Joe Tsaibfda0142018-08-10 13:58:07 -070033func TestFile(t *testing.T) {
Joe Tsaid8881392019-06-06 13:01:53 -070034 f1 := &descriptorpb.FileDescriptorProto{
Joe Tsai009e0672018-11-27 18:45:07 -080035 Syntax: scalar.String("proto2"),
36 Name: scalar.String("path/to/file.proto"),
37 Package: scalar.String("test"),
Joe Tsaie1f8d502018-11-26 18:55:29 -080038 Options: &descriptorpb.FileOptions{Deprecated: scalar.Bool(true)},
39 MessageType: []*descriptorpb.DescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -080040 Name: scalar.String("A"),
Joe Tsaie1f8d502018-11-26 18:55:29 -080041 Options: &descriptorpb.MessageOptions{
Joe Tsai009e0672018-11-27 18:45:07 -080042 MapEntry: scalar.Bool(true),
43 Deprecated: scalar.Bool(true),
Damien Neil204f1c02018-10-23 15:03:38 -070044 },
Joe Tsaie1f8d502018-11-26 18:55:29 -080045 Field: []*descriptorpb.FieldDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -080046 Name: scalar.String("key"),
47 Number: scalar.Int32(1),
Joe Tsaie1f8d502018-11-26 18:55:29 -080048 Options: &descriptorpb.FieldOptions{Deprecated: scalar.Bool(true)},
49 Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
50 Type: descriptorpb.FieldDescriptorProto_Type(pref.StringKind).Enum(),
Joe Tsai23ddbd12018-08-26 22:48:17 -070051 }, {
Joe Tsai009e0672018-11-27 18:45:07 -080052 Name: scalar.String("value"),
53 Number: scalar.Int32(2),
Joe Tsaie1f8d502018-11-26 18:55:29 -080054 Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
55 Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
Joe Tsai009e0672018-11-27 18:45:07 -080056 TypeName: scalar.String(".test.B"),
Joe Tsai23ddbd12018-08-26 22:48:17 -070057 }},
58 }, {
Joe Tsai009e0672018-11-27 18:45:07 -080059 Name: scalar.String("B"),
Joe Tsaie1f8d502018-11-26 18:55:29 -080060 Field: []*descriptorpb.FieldDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -080061 Name: scalar.String("field_one"),
62 Number: scalar.Int32(1),
Joe Tsaie1f8d502018-11-26 18:55:29 -080063 Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
64 Type: descriptorpb.FieldDescriptorProto_Type(pref.StringKind).Enum(),
Joe Tsai009e0672018-11-27 18:45:07 -080065 DefaultValue: scalar.String("hello, \"world!\"\n"),
66 OneofIndex: scalar.Int32(0),
Joe Tsai23ddbd12018-08-26 22:48:17 -070067 }, {
Joe Tsai009e0672018-11-27 18:45:07 -080068 Name: scalar.String("field_two"),
69 JsonName: scalar.String("Field2"),
70 Number: scalar.Int32(2),
Joe Tsaie1f8d502018-11-26 18:55:29 -080071 Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
72 Type: descriptorpb.FieldDescriptorProto_Type(pref.EnumKind).Enum(),
Joe Tsai009e0672018-11-27 18:45:07 -080073 DefaultValue: scalar.String("BAR"),
74 TypeName: scalar.String(".test.E1"),
75 OneofIndex: scalar.Int32(1),
Joe Tsai23ddbd12018-08-26 22:48:17 -070076 }, {
Joe Tsai009e0672018-11-27 18:45:07 -080077 Name: scalar.String("field_three"),
78 Number: scalar.Int32(3),
Joe Tsaie1f8d502018-11-26 18:55:29 -080079 Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
80 Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
Joe Tsai009e0672018-11-27 18:45:07 -080081 TypeName: scalar.String(".test.C"),
82 OneofIndex: scalar.Int32(1),
Joe Tsai23ddbd12018-08-26 22:48:17 -070083 }, {
Joe Tsai009e0672018-11-27 18:45:07 -080084 Name: scalar.String("field_four"),
85 JsonName: scalar.String("Field4"),
86 Number: scalar.Int32(4),
Joe Tsaie1f8d502018-11-26 18:55:29 -080087 Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
88 Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
Joe Tsai009e0672018-11-27 18:45:07 -080089 TypeName: scalar.String(".test.A"),
Joe Tsai23ddbd12018-08-26 22:48:17 -070090 }, {
Joe Tsai009e0672018-11-27 18:45:07 -080091 Name: scalar.String("field_five"),
92 Number: scalar.Int32(5),
Joe Tsaie1f8d502018-11-26 18:55:29 -080093 Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
94 Type: descriptorpb.FieldDescriptorProto_Type(pref.Int32Kind).Enum(),
95 Options: &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
Joe Tsai23ddbd12018-08-26 22:48:17 -070096 }, {
Joe Tsai009e0672018-11-27 18:45:07 -080097 Name: scalar.String("field_six"),
98 Number: scalar.Int32(6),
Joe Tsaie1f8d502018-11-26 18:55:29 -080099 Label: descriptorpb.FieldDescriptorProto_Label(pref.Required).Enum(),
100 Type: descriptorpb.FieldDescriptorProto_Type(pref.BytesKind).Enum(),
Joe Tsai23ddbd12018-08-26 22:48:17 -0700101 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800102 OneofDecl: []*descriptorpb.OneofDescriptorProto{
Damien Neil204f1c02018-10-23 15:03:38 -0700103 {
Joe Tsai009e0672018-11-27 18:45:07 -0800104 Name: scalar.String("O1"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800105 Options: &descriptorpb.OneofOptions{
106 UninterpretedOption: []*descriptorpb.UninterpretedOption{
Damien Neil204f1c02018-10-23 15:03:38 -0700107 {StringValue: []byte("option")},
108 },
109 },
110 },
Joe Tsai009e0672018-11-27 18:45:07 -0800111 {Name: scalar.String("O2")},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700112 },
Joe Tsaibce82b82018-12-06 09:39:03 -0800113 ReservedName: []string{"fizz", "buzz"},
114 ReservedRange: []*descriptorpb.DescriptorProto_ReservedRange{
115 {Start: scalar.Int32(100), End: scalar.Int32(200)},
116 {Start: scalar.Int32(300), End: scalar.Int32(301)},
117 },
Joe Tsaie1f8d502018-11-26 18:55:29 -0800118 ExtensionRange: []*descriptorpb.DescriptorProto_ExtensionRange{
Joe Tsai009e0672018-11-27 18:45:07 -0800119 {Start: scalar.Int32(1000), End: scalar.Int32(2000)},
Joe Tsai381f04c2018-12-06 12:10:41 -0800120 {Start: scalar.Int32(3000), End: scalar.Int32(3001), Options: new(descriptorpb.ExtensionRangeOptions)},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700121 },
122 }, {
Joe Tsai009e0672018-11-27 18:45:07 -0800123 Name: scalar.String("C"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800124 NestedType: []*descriptorpb.DescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -0800125 Name: scalar.String("A"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800126 Field: []*descriptorpb.FieldDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -0800127 Name: scalar.String("F"),
128 Number: scalar.Int32(1),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800129 Label: descriptorpb.FieldDescriptorProto_Label(pref.Required).Enum(),
130 Type: descriptorpb.FieldDescriptorProto_Type(pref.BytesKind).Enum(),
Joe Tsai009e0672018-11-27 18:45:07 -0800131 DefaultValue: scalar.String(`dead\276\357`),
Joe Tsai23ddbd12018-08-26 22:48:17 -0700132 }},
133 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800134 EnumType: []*descriptorpb.EnumDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -0800135 Name: scalar.String("E1"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800136 Value: []*descriptorpb.EnumValueDescriptorProto{
Joe Tsai009e0672018-11-27 18:45:07 -0800137 {Name: scalar.String("FOO"), Number: scalar.Int32(0)},
138 {Name: scalar.String("BAR"), Number: scalar.Int32(1)},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700139 },
140 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800141 Extension: []*descriptorpb.FieldDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -0800142 Name: scalar.String("X"),
143 Number: scalar.Int32(1000),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800144 Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
145 Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
Joe Tsai009e0672018-11-27 18:45:07 -0800146 TypeName: scalar.String(".test.C"),
147 Extendee: scalar.String(".test.B"),
Joe Tsai23ddbd12018-08-26 22:48:17 -0700148 }},
149 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800150 EnumType: []*descriptorpb.EnumDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -0800151 Name: scalar.String("E1"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800152 Options: &descriptorpb.EnumOptions{Deprecated: scalar.Bool(true)},
153 Value: []*descriptorpb.EnumValueDescriptorProto{
Damien Neil204f1c02018-10-23 15:03:38 -0700154 {
Joe Tsai009e0672018-11-27 18:45:07 -0800155 Name: scalar.String("FOO"),
156 Number: scalar.Int32(0),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800157 Options: &descriptorpb.EnumValueOptions{Deprecated: scalar.Bool(true)},
Damien Neil204f1c02018-10-23 15:03:38 -0700158 },
Joe Tsai009e0672018-11-27 18:45:07 -0800159 {Name: scalar.String("BAR"), Number: scalar.Int32(1)},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700160 },
Joe Tsaibce82b82018-12-06 09:39:03 -0800161 ReservedName: []string{"FIZZ", "BUZZ"},
162 ReservedRange: []*descriptorpb.EnumDescriptorProto_EnumReservedRange{
163 {Start: scalar.Int32(10), End: scalar.Int32(19)},
164 {Start: scalar.Int32(30), End: scalar.Int32(30)},
165 },
Joe Tsai23ddbd12018-08-26 22:48:17 -0700166 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800167 Extension: []*descriptorpb.FieldDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -0800168 Name: scalar.String("X"),
169 Number: scalar.Int32(1000),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800170 Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
171 Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
172 Options: &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
Joe Tsai009e0672018-11-27 18:45:07 -0800173 TypeName: scalar.String(".test.C"),
174 Extendee: scalar.String(".test.B"),
Joe Tsai23ddbd12018-08-26 22:48:17 -0700175 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800176 Service: []*descriptorpb.ServiceDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -0800177 Name: scalar.String("S"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800178 Options: &descriptorpb.ServiceOptions{Deprecated: scalar.Bool(true)},
179 Method: []*descriptorpb.MethodDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -0800180 Name: scalar.String("M"),
181 InputType: scalar.String(".test.A"),
182 OutputType: scalar.String(".test.C.A"),
183 ClientStreaming: scalar.Bool(true),
184 ServerStreaming: scalar.Bool(true),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800185 Options: &descriptorpb.MethodOptions{Deprecated: scalar.Bool(true)},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700186 }},
187 }},
188 }
Joe Tsaid8881392019-06-06 13:01:53 -0700189 fd1, err := pdesc.NewFile(f1, nil)
Joe Tsai23ddbd12018-08-26 22:48:17 -0700190 if err != nil {
Joe Tsaie1f8d502018-11-26 18:55:29 -0800191 t.Fatalf("protodesc.NewFile() error: %v", err)
Joe Tsai23ddbd12018-08-26 22:48:17 -0700192 }
193
Joe Tsaid8881392019-06-06 13:01:53 -0700194 b, err := proto.Marshal(f1)
195 if err != nil {
196 t.Fatalf("proto.Marshal() error: %v", err)
197 }
198 fd2 := filedesc.DescBuilder{RawDescriptor: b}.Build().File
199
Joe Tsai23ddbd12018-08-26 22:48:17 -0700200 tests := []struct {
201 name string
202 desc pref.FileDescriptor
203 }{
Joe Tsaid8881392019-06-06 13:01:53 -0700204 {"protodesc.NewFile", fd1},
205 {"filedesc.DescBuilder.Build", fd2},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700206 }
207 for _, tt := range tests {
Joe Tsai17764982018-08-24 03:03:21 -0700208 tt := tt
Joe Tsai23ddbd12018-08-26 22:48:17 -0700209 t.Run(tt.name, func(t *testing.T) {
Joe Tsai17764982018-08-24 03:03:21 -0700210 // Run sub-tests in parallel to induce potential races.
211 for i := 0; i < 2; i++ {
212 t.Run("Accessors", func(t *testing.T) { t.Parallel(); testFileAccessors(t, tt.desc) })
Joe Tsaidd00a272018-09-13 12:50:58 -0700213 t.Run("Format", func(t *testing.T) { t.Parallel(); testFileFormat(t, tt.desc) })
Joe Tsai17764982018-08-24 03:03:21 -0700214 }
Joe Tsai23ddbd12018-08-26 22:48:17 -0700215 })
216 }
217}
218
219func testFileAccessors(t *testing.T, fd pref.FileDescriptor) {
Joe Tsaibfda0142018-08-10 13:58:07 -0700220 // Represent the descriptor as a map where each key is an accessor method
221 // and the value is either the wanted tail value or another accessor map.
222 type M = map[string]interface{}
223 want := M{
224 "Parent": nil,
Damien Neil3de06c02018-09-07 09:39:44 -0700225 "Index": 0,
Joe Tsaibfda0142018-08-10 13:58:07 -0700226 "Syntax": pref.Proto2,
227 "Name": pref.Name("test"),
228 "FullName": pref.FullName("test"),
229 "Path": "path/to/file.proto",
230 "Package": pref.FullName("test"),
231 "IsPlaceholder": false,
Joe Tsaie1f8d502018-11-26 18:55:29 -0800232 "Options": &descriptorpb.FileOptions{Deprecated: scalar.Bool(true)},
Joe Tsaibfda0142018-08-10 13:58:07 -0700233 "Messages": M{
234 "Len": 3,
235 "Get:0": M{
236 "Parent": M{"FullName": pref.FullName("test")},
Damien Neil3de06c02018-09-07 09:39:44 -0700237 "Index": 0,
Joe Tsaibfda0142018-08-10 13:58:07 -0700238 "Syntax": pref.Proto2,
239 "Name": pref.Name("A"),
240 "FullName": pref.FullName("test.A"),
241 "IsPlaceholder": false,
242 "IsMapEntry": true,
Joe Tsaie1f8d502018-11-26 18:55:29 -0800243 "Options": &descriptorpb.MessageOptions{
Joe Tsai009e0672018-11-27 18:45:07 -0800244 MapEntry: scalar.Bool(true),
245 Deprecated: scalar.Bool(true),
Damien Neil204f1c02018-10-23 15:03:38 -0700246 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700247 "Fields": M{
248 "Len": 2,
249 "ByNumber:1": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700250 "Parent": M{"FullName": pref.FullName("test.A")},
251 "Index": 0,
252 "Name": pref.Name("key"),
253 "FullName": pref.FullName("test.A.key"),
254 "Number": pref.FieldNumber(1),
255 "Cardinality": pref.Optional,
256 "Kind": pref.StringKind,
257 "Options": &descriptorpb.FieldOptions{Deprecated: scalar.Bool(true)},
258 "HasJSONName": false,
259 "JSONName": "key",
260 "IsPacked": false,
261 "IsList": false,
262 "IsMap": false,
263 "IsExtension": false,
264 "IsWeak": false,
265 "Default": "",
266 "ContainingOneof": nil,
267 "ContainingMessage": M{"FullName": pref.FullName("test.A")},
268 "Message": nil,
269 "Enum": nil,
Joe Tsaibfda0142018-08-10 13:58:07 -0700270 },
271 "ByNumber:2": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700272 "Parent": M{"FullName": pref.FullName("test.A")},
273 "Index": 1,
274 "Name": pref.Name("value"),
275 "FullName": pref.FullName("test.A.value"),
276 "Number": pref.FieldNumber(2),
277 "Cardinality": pref.Optional,
278 "Kind": pref.MessageKind,
279 "JSONName": "value",
280 "IsPacked": false,
281 "IsList": false,
282 "IsMap": false,
283 "IsExtension": false,
284 "IsWeak": false,
285 "Default": nil,
286 "ContainingOneof": nil,
287 "ContainingMessage": M{"FullName": pref.FullName("test.A")},
288 "Message": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
289 "Enum": nil,
Joe Tsaibfda0142018-08-10 13:58:07 -0700290 },
291 "ByNumber:3": nil,
292 },
293 "Oneofs": M{"Len": 0},
294 "RequiredNumbers": M{"Len": 0},
295 "ExtensionRanges": M{"Len": 0},
296 "Messages": M{"Len": 0},
297 "Enums": M{"Len": 0},
298 "Extensions": M{"Len": 0},
299 },
300 "ByName:B": M{
Damien Neil3de06c02018-09-07 09:39:44 -0700301 "Name": pref.Name("B"),
302 "Index": 1,
Joe Tsaibfda0142018-08-10 13:58:07 -0700303 "Fields": M{
304 "Len": 6,
305 "ByJSONName:field_one": nil,
306 "ByJSONName:fieldOne": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700307 "Name": pref.Name("field_one"),
308 "Index": 0,
309 "JSONName": "fieldOne",
310 "Default": "hello, \"world!\"\n",
311 "ContainingOneof": M{"Name": pref.Name("O1"), "IsPlaceholder": false},
312 "ContainingMessage": M{"FullName": pref.FullName("test.B")},
Joe Tsaibfda0142018-08-10 13:58:07 -0700313 },
314 "ByJSONName:fieldTwo": nil,
315 "ByJSONName:Field2": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700316 "Name": pref.Name("field_two"),
317 "Index": 1,
318 "HasJSONName": true,
319 "JSONName": "Field2",
320 "Default": pref.EnumNumber(1),
321 "ContainingOneof": M{"Name": pref.Name("O2"), "IsPlaceholder": false},
Joe Tsaibfda0142018-08-10 13:58:07 -0700322 },
323 "ByName:fieldThree": nil,
324 "ByName:field_three": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700325 "IsExtension": false,
326 "IsMap": false,
327 "MapKey": nil,
328 "MapValue": nil,
329 "Message": M{"FullName": pref.FullName("test.C"), "IsPlaceholder": false},
330 "ContainingOneof": M{"Name": pref.Name("O2"), "IsPlaceholder": false},
331 "ContainingMessage": M{"FullName": pref.FullName("test.B")},
Joe Tsaibfda0142018-08-10 13:58:07 -0700332 },
333 "ByNumber:12": nil,
334 "ByNumber:4": M{
335 "Cardinality": pref.Repeated,
Joe Tsaiac31a352019-05-13 14:32:56 -0700336 "IsExtension": false,
337 "IsList": false,
Joe Tsaibfda0142018-08-10 13:58:07 -0700338 "IsMap": true,
Joe Tsaiac31a352019-05-13 14:32:56 -0700339 "MapKey": M{"Kind": pref.StringKind},
340 "MapValue": M{"Kind": pref.MessageKind, "Message": M{"FullName": pref.FullName("test.B")}},
Joe Tsaibfda0142018-08-10 13:58:07 -0700341 "Default": nil,
Joe Tsaid24bc722019-04-15 23:39:09 -0700342 "Message": M{"FullName": pref.FullName("test.A"), "IsPlaceholder": false},
Joe Tsaibfda0142018-08-10 13:58:07 -0700343 },
344 "ByNumber:5": M{
345 "Cardinality": pref.Repeated,
346 "Kind": pref.Int32Kind,
347 "IsPacked": true,
Joe Tsaiac31a352019-05-13 14:32:56 -0700348 "IsList": true,
349 "IsMap": false,
Joe Tsaibfda0142018-08-10 13:58:07 -0700350 "Default": int32(0),
351 },
352 "ByNumber:6": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700353 "Cardinality": pref.Required,
354 "Default": []byte(nil),
355 "ContainingOneof": nil,
Joe Tsaibfda0142018-08-10 13:58:07 -0700356 },
357 },
358 "Oneofs": M{
359 "Len": 2,
360 "ByName:O0": nil,
361 "ByName:O1": M{
362 "FullName": pref.FullName("test.B.O1"),
Damien Neil3de06c02018-09-07 09:39:44 -0700363 "Index": 0,
Joe Tsaie1f8d502018-11-26 18:55:29 -0800364 "Options": &descriptorpb.OneofOptions{
365 UninterpretedOption: []*descriptorpb.UninterpretedOption{
Damien Neil204f1c02018-10-23 15:03:38 -0700366 {StringValue: []byte("option")},
367 },
368 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700369 "Fields": M{
370 "Len": 1,
371 "Get:0": M{"FullName": pref.FullName("test.B.field_one")},
372 },
373 },
374 "Get:1": M{
375 "FullName": pref.FullName("test.B.O2"),
Damien Neil3de06c02018-09-07 09:39:44 -0700376 "Index": 1,
Joe Tsaibfda0142018-08-10 13:58:07 -0700377 "Fields": M{
378 "Len": 2,
379 "ByName:field_two": M{"Name": pref.Name("field_two")},
380 "Get:1": M{"Name": pref.Name("field_three")},
381 },
382 },
383 },
Joe Tsaibce82b82018-12-06 09:39:03 -0800384 "ReservedNames": M{
385 "Len": 2,
386 "Get:0": pref.Name("fizz"),
387 "Has:buzz": true,
388 "Has:noexist": false,
389 },
390 "ReservedRanges": M{
391 "Len": 2,
392 "Get:0": [2]pref.FieldNumber{100, 200},
393 "Has:99": false,
394 "Has:100": true,
395 "Has:150": true,
396 "Has:199": true,
397 "Has:200": false,
398 "Has:300": true,
399 "Has:301": false,
400 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700401 "RequiredNumbers": M{
402 "Len": 1,
403 "Get:0": pref.FieldNumber(6),
404 "Has:1": false,
405 "Has:6": true,
406 },
407 "ExtensionRanges": M{
Joe Tsai17764982018-08-24 03:03:21 -0700408 "Len": 2,
Joe Tsaibfda0142018-08-10 13:58:07 -0700409 "Get:0": [2]pref.FieldNumber{1000, 2000},
410 "Has:999": false,
411 "Has:1000": true,
412 "Has:1500": true,
413 "Has:1999": true,
414 "Has:2000": false,
Joe Tsai17764982018-08-24 03:03:21 -0700415 "Has:3000": true,
Joe Tsaibce82b82018-12-06 09:39:03 -0800416 "Has:3001": false,
Joe Tsaibfda0142018-08-10 13:58:07 -0700417 },
Joe Tsai381f04c2018-12-06 12:10:41 -0800418 "ExtensionRangeOptions:0": (*descriptorpb.ExtensionRangeOptions)(nil),
419 "ExtensionRangeOptions:1": new(descriptorpb.ExtensionRangeOptions),
Joe Tsaibfda0142018-08-10 13:58:07 -0700420 },
421 "Get:2": M{
Damien Neil3de06c02018-09-07 09:39:44 -0700422 "Name": pref.Name("C"),
423 "Index": 2,
Joe Tsaibfda0142018-08-10 13:58:07 -0700424 "Messages": M{
425 "Len": 1,
426 "Get:0": M{"FullName": pref.FullName("test.C.A")},
427 },
428 "Enums": M{
429 "Len": 1,
430 "Get:0": M{"FullName": pref.FullName("test.C.E1")},
431 },
432 "Extensions": M{
433 "Len": 1,
434 "Get:0": M{"FullName": pref.FullName("test.C.X")},
435 },
436 },
437 },
438 "Enums": M{
439 "Len": 1,
440 "Get:0": M{
Damien Neil204f1c02018-10-23 15:03:38 -0700441 "Name": pref.Name("E1"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800442 "Options": &descriptorpb.EnumOptions{Deprecated: scalar.Bool(true)},
Joe Tsaibfda0142018-08-10 13:58:07 -0700443 "Values": M{
444 "Len": 2,
445 "ByName:Foo": nil,
Damien Neil204f1c02018-10-23 15:03:38 -0700446 "ByName:FOO": M{
447 "FullName": pref.FullName("test.FOO"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800448 "Options": &descriptorpb.EnumValueOptions{Deprecated: scalar.Bool(true)},
Damien Neil204f1c02018-10-23 15:03:38 -0700449 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700450 "ByNumber:2": nil,
451 "ByNumber:1": M{"FullName": pref.FullName("test.BAR")},
452 },
Joe Tsaibce82b82018-12-06 09:39:03 -0800453 "ReservedNames": M{
454 "Len": 2,
455 "Get:0": pref.Name("FIZZ"),
456 "Has:BUZZ": true,
457 "Has:NOEXIST": false,
458 },
459 "ReservedRanges": M{
460 "Len": 2,
461 "Get:0": [2]pref.EnumNumber{10, 19},
462 "Has:9": false,
463 "Has:10": true,
464 "Has:15": true,
465 "Has:19": true,
466 "Has:20": false,
467 "Has:30": true,
468 "Has:31": false,
469 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700470 },
471 },
472 "Extensions": M{
473 "Len": 1,
474 "ByName:X": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700475 "Name": pref.Name("X"),
476 "Number": pref.FieldNumber(1000),
477 "Cardinality": pref.Repeated,
478 "Kind": pref.MessageKind,
479 "IsExtension": true,
Joe Tsaid8881392019-06-06 13:01:53 -0700480 "IsPacked": true,
Joe Tsaiac31a352019-05-13 14:32:56 -0700481 "IsList": true,
482 "IsMap": false,
483 "MapKey": nil,
484 "MapValue": nil,
485 "ContainingOneof": nil,
486 "ContainingMessage": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
487 "Message": M{"FullName": pref.FullName("test.C"), "IsPlaceholder": false},
488 "Options": &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
Joe Tsaibfda0142018-08-10 13:58:07 -0700489 },
490 },
491 "Services": M{
492 "Len": 1,
493 "ByName:s": nil,
494 "ByName:S": M{
495 "Parent": M{"FullName": pref.FullName("test")},
496 "Name": pref.Name("S"),
497 "FullName": pref.FullName("test.S"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800498 "Options": &descriptorpb.ServiceOptions{Deprecated: scalar.Bool(true)},
Joe Tsaibfda0142018-08-10 13:58:07 -0700499 "Methods": M{
500 "Len": 1,
501 "Get:0": M{
502 "Parent": M{"FullName": pref.FullName("test.S")},
503 "Name": pref.Name("M"),
504 "FullName": pref.FullName("test.S.M"),
Joe Tsaid24bc722019-04-15 23:39:09 -0700505 "Input": M{"FullName": pref.FullName("test.A"), "IsPlaceholder": false},
506 "Output": M{"FullName": pref.FullName("test.C.A"), "IsPlaceholder": false},
Joe Tsaibfda0142018-08-10 13:58:07 -0700507 "IsStreamingClient": true,
508 "IsStreamingServer": true,
Joe Tsaie1f8d502018-11-26 18:55:29 -0800509 "Options": &descriptorpb.MethodOptions{Deprecated: scalar.Bool(true)},
Joe Tsaibfda0142018-08-10 13:58:07 -0700510 },
511 },
512 },
513 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700514 }
Joe Tsai23ddbd12018-08-26 22:48:17 -0700515 checkAccessors(t, "", reflect.ValueOf(fd), want)
Joe Tsaibfda0142018-08-10 13:58:07 -0700516}
Joe Tsaibfda0142018-08-10 13:58:07 -0700517func checkAccessors(t *testing.T, p string, rv reflect.Value, want map[string]interface{}) {
Joe Tsaie1f8d502018-11-26 18:55:29 -0800518 p0 := p
519 defer func() {
520 if ex := recover(); ex != nil {
521 t.Errorf("panic at %v: %v", p, ex)
522 }
523 }()
524
Joe Tsaibfda0142018-08-10 13:58:07 -0700525 if rv.Interface() == nil {
526 t.Errorf("%v is nil, want non-nil", p)
527 return
528 }
529 for s, v := range want {
530 // Call the accessor method.
Joe Tsaie1f8d502018-11-26 18:55:29 -0800531 p = p0 + "." + s
Joe Tsaibfda0142018-08-10 13:58:07 -0700532 var rets []reflect.Value
533 if i := strings.IndexByte(s, ':'); i >= 0 {
534 // Accessor method takes in a single argument, which is encoded
535 // after the accessor name, separated by a ':' delimiter.
536 fnc := rv.MethodByName(s[:i])
537 arg := reflect.New(fnc.Type().In(0)).Elem()
538 s = s[i+len(":"):]
539 switch arg.Kind() {
540 case reflect.String:
541 arg.SetString(s)
542 case reflect.Int32, reflect.Int:
543 n, _ := strconv.ParseInt(s, 0, 64)
544 arg.SetInt(n)
545 }
546 rets = fnc.Call([]reflect.Value{arg})
547 } else {
548 rets = rv.MethodByName(s).Call(nil)
549 }
550
551 // Check that (val, ok) pattern is internally consistent.
552 if len(rets) == 2 {
553 if rets[0].IsNil() && rets[1].Bool() {
554 t.Errorf("%v = (nil, true), want (nil, false)", p)
555 }
556 if !rets[0].IsNil() && !rets[1].Bool() {
557 t.Errorf("%v = (non-nil, false), want (non-nil, true)", p)
558 }
559 }
560
561 // Check that the accessor output matches.
562 if want, ok := v.(map[string]interface{}); ok {
563 checkAccessors(t, p, rets[0], want)
Damien Neil204f1c02018-10-23 15:03:38 -0700564 continue
565 }
566
567 got := rets[0].Interface()
568 if pv, ok := got.(pref.Value); ok {
569 got = pv.Interface()
570 }
571
572 // Compare with proto.Equal if possible.
Joe Tsaid8881392019-06-06 13:01:53 -0700573 gotMsg, gotMsgOK := got.(proto.Message)
574 wantMsg, wantMsgOK := v.(proto.Message)
Damien Neil204f1c02018-10-23 15:03:38 -0700575 if gotMsgOK && wantMsgOK {
Joe Tsaid8881392019-06-06 13:01:53 -0700576 gotNil := reflect.ValueOf(gotMsg).IsNil()
577 wantNil := reflect.ValueOf(wantMsg).IsNil()
578 switch {
579 case !gotNil && wantNil:
580 t.Errorf("%v = non-nil, want nil", p)
581 case gotNil && !wantNil:
582 t.Errorf("%v = nil, want non-nil", p)
583 case !proto.Equal(gotMsg, wantMsg):
584 t.Errorf("%v = %v, want %v", p, gotMsg, wantMsg)
Joe Tsaibfda0142018-08-10 13:58:07 -0700585 }
Damien Neil204f1c02018-10-23 15:03:38 -0700586 continue
587 }
588
589 if want := v; !reflect.DeepEqual(got, want) {
Joe Tsai381f04c2018-12-06 12:10:41 -0800590 t.Errorf("%v = %T(%v), want %T(%v)", p, got, got, want, want)
Joe Tsaibfda0142018-08-10 13:58:07 -0700591 }
592 }
593}
594
Joe Tsaidd00a272018-09-13 12:50:58 -0700595func testFileFormat(t *testing.T, fd pref.FileDescriptor) {
Joe Tsai17764982018-08-24 03:03:21 -0700596 const want = `FileDescriptor{
597 Syntax: proto2
598 Path: "path/to/file.proto"
599 Package: test
600 Messages: [{
601 Name: A
602 IsMapEntry: true
603 Fields: [{
604 Name: key
605 Number: 1
606 Cardinality: optional
607 Kind: string
608 JSONName: "key"
609 }, {
610 Name: value
611 Number: 2
612 Cardinality: optional
613 Kind: message
614 JSONName: "value"
Joe Tsaid24bc722019-04-15 23:39:09 -0700615 Message: test.B
Joe Tsai17764982018-08-24 03:03:21 -0700616 }]
617 }, {
618 Name: B
619 Fields: [{
620 Name: field_one
621 Number: 1
622 Cardinality: optional
623 Kind: string
624 JSONName: "fieldOne"
Damien Neile6fa22a2018-09-12 15:15:40 -0700625 HasDefault: true
Joe Tsai1dab2cb2018-09-28 13:39:07 -0700626 Default: "hello, \"world!\"\n"
Joe Tsaid24bc722019-04-15 23:39:09 -0700627 Oneof: O1
Joe Tsai17764982018-08-24 03:03:21 -0700628 }, {
629 Name: field_two
630 Number: 2
631 Cardinality: optional
632 Kind: enum
Joe Tsaibce82b82018-12-06 09:39:03 -0800633 HasJSONName: true
Joe Tsai17764982018-08-24 03:03:21 -0700634 JSONName: "Field2"
Damien Neile6fa22a2018-09-12 15:15:40 -0700635 HasDefault: true
Joe Tsai17764982018-08-24 03:03:21 -0700636 Default: 1
Joe Tsaid24bc722019-04-15 23:39:09 -0700637 Oneof: O2
638 Enum: test.E1
Joe Tsai17764982018-08-24 03:03:21 -0700639 }, {
640 Name: field_three
641 Number: 3
642 Cardinality: optional
643 Kind: message
644 JSONName: "fieldThree"
Joe Tsaid24bc722019-04-15 23:39:09 -0700645 Oneof: O2
646 Message: test.C
Joe Tsai17764982018-08-24 03:03:21 -0700647 }, {
648 Name: field_four
649 Number: 4
650 Cardinality: repeated
651 Kind: message
Joe Tsaibce82b82018-12-06 09:39:03 -0800652 HasJSONName: true
Joe Tsai17764982018-08-24 03:03:21 -0700653 JSONName: "Field4"
654 IsMap: true
Joe Tsaiac31a352019-05-13 14:32:56 -0700655 MapKey: string
656 MapValue: test.B
Joe Tsai17764982018-08-24 03:03:21 -0700657 }, {
658 Name: field_five
659 Number: 5
660 Cardinality: repeated
661 Kind: int32
662 JSONName: "fieldFive"
663 IsPacked: true
Joe Tsaiac31a352019-05-13 14:32:56 -0700664 IsList: true
Joe Tsai17764982018-08-24 03:03:21 -0700665 }, {
666 Name: field_six
667 Number: 6
668 Cardinality: required
669 Kind: bytes
670 JSONName: "fieldSix"
671 }]
672 Oneofs: [{
673 Name: O1
674 Fields: [field_one]
675 }, {
676 Name: O2
677 Fields: [field_two, field_three]
678 }]
Joe Tsaibce82b82018-12-06 09:39:03 -0800679 ReservedNames: [fizz, buzz]
680 ReservedRanges: [100:200, 300]
Joe Tsai17764982018-08-24 03:03:21 -0700681 RequiredNumbers: [6]
682 ExtensionRanges: [1000:2000, 3000]
683 }, {
684 Name: C
685 Messages: [{
686 Name: A
687 Fields: [{
688 Name: F
689 Number: 1
690 Cardinality: required
691 Kind: bytes
692 JSONName: "F"
Damien Neile6fa22a2018-09-12 15:15:40 -0700693 HasDefault: true
Joe Tsai17764982018-08-24 03:03:21 -0700694 Default: "dead\xbe\xef"
695 }]
696 RequiredNumbers: [1]
697 }]
698 Enums: [{
699 Name: E1
700 Values: [
701 {Name: FOO}
702 {Name: BAR, Number: 1}
703 ]
704 }]
705 Extensions: [{
Joe Tsaid24bc722019-04-15 23:39:09 -0700706 Name: X
707 Number: 1000
708 Cardinality: repeated
709 Kind: message
Joe Tsaid8881392019-06-06 13:01:53 -0700710 JSONName: "X"
Joe Tsaiac31a352019-05-13 14:32:56 -0700711 IsExtension: true
712 IsList: true
Joe Tsaid24bc722019-04-15 23:39:09 -0700713 Extendee: test.B
714 Message: test.C
Joe Tsai17764982018-08-24 03:03:21 -0700715 }]
716 }]
717 Enums: [{
718 Name: E1
719 Values: [
720 {Name: FOO}
721 {Name: BAR, Number: 1}
722 ]
Joe Tsaibce82b82018-12-06 09:39:03 -0800723 ReservedNames: [FIZZ, BUZZ]
724 ReservedRanges: [10:20, 30]
Joe Tsai17764982018-08-24 03:03:21 -0700725 }]
726 Extensions: [{
Joe Tsaid24bc722019-04-15 23:39:09 -0700727 Name: X
728 Number: 1000
729 Cardinality: repeated
730 Kind: message
Joe Tsaid8881392019-06-06 13:01:53 -0700731 JSONName: "X"
732 IsPacked: true
Joe Tsaiac31a352019-05-13 14:32:56 -0700733 IsExtension: true
734 IsList: true
Joe Tsaid24bc722019-04-15 23:39:09 -0700735 Extendee: test.B
736 Message: test.C
Joe Tsai17764982018-08-24 03:03:21 -0700737 }]
738 Services: [{
739 Name: S
740 Methods: [{
741 Name: M
Joe Tsaid24bc722019-04-15 23:39:09 -0700742 Input: test.A
743 Output: test.C.A
Joe Tsai17764982018-08-24 03:03:21 -0700744 IsStreamingClient: true
745 IsStreamingServer: true
746 }]
747 }]
748}`
Joe Tsaidd00a272018-09-13 12:50:58 -0700749 tests := []struct{ fmt, want string }{{"%v", compactMultiFormat(want)}, {"%+v", want}}
750 for _, tt := range tests {
751 got := fmt.Sprintf(tt.fmt, fd)
Joe Tsaiac31a352019-05-13 14:32:56 -0700752 if diff := cmp.Diff(got, tt.want); diff != "" {
753 t.Errorf("fmt.Sprintf(%q, fd) mismatch (-got +want):\n%s", tt.fmt, diff)
Joe Tsaidd00a272018-09-13 12:50:58 -0700754 }
Joe Tsai17764982018-08-24 03:03:21 -0700755 }
756}
757
Joe Tsaidd00a272018-09-13 12:50:58 -0700758// compactMultiFormat returns the single line form of a multi line output.
759func compactMultiFormat(s string) string {
760 var b []byte
761 for _, s := range strings.Split(s, "\n") {
762 s = strings.TrimSpace(s)
763 s = regexp.MustCompile(": +").ReplaceAllString(s, ": ")
764 prevWord := len(b) > 0 && b[len(b)-1] != '[' && b[len(b)-1] != '{'
765 nextWord := len(s) > 0 && s[0] != ']' && s[0] != '}'
766 if prevWord && nextWord {
767 b = append(b, ", "...)
768 }
769 b = append(b, s...)
770 }
771 return string(b)
772}