blob: 66ce518373961d3b7456b0d9ce22661c672fcf97 [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 Deprecated: scalar.Bool(true),
Damien Neil204f1c02018-10-23 15:03:38 -070043 },
Joe Tsai23ddbd12018-08-26 22:48:17 -070044 }, {
Joe Tsai009e0672018-11-27 18:45:07 -080045 Name: scalar.String("B"),
Joe Tsaie1f8d502018-11-26 18:55:29 -080046 Field: []*descriptorpb.FieldDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -080047 Name: scalar.String("field_one"),
48 Number: scalar.Int32(1),
Joe Tsaie1f8d502018-11-26 18:55:29 -080049 Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
50 Type: descriptorpb.FieldDescriptorProto_Type(pref.StringKind).Enum(),
Joe Tsai009e0672018-11-27 18:45:07 -080051 DefaultValue: scalar.String("hello, \"world!\"\n"),
52 OneofIndex: scalar.Int32(0),
Joe Tsai23ddbd12018-08-26 22:48:17 -070053 }, {
Joe Tsai009e0672018-11-27 18:45:07 -080054 Name: scalar.String("field_two"),
55 JsonName: scalar.String("Field2"),
56 Number: scalar.Int32(2),
Joe Tsaie1f8d502018-11-26 18:55:29 -080057 Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
58 Type: descriptorpb.FieldDescriptorProto_Type(pref.EnumKind).Enum(),
Joe Tsai009e0672018-11-27 18:45:07 -080059 DefaultValue: scalar.String("BAR"),
60 TypeName: scalar.String(".test.E1"),
61 OneofIndex: scalar.Int32(1),
Joe Tsai23ddbd12018-08-26 22:48:17 -070062 }, {
Joe Tsai009e0672018-11-27 18:45:07 -080063 Name: scalar.String("field_three"),
64 Number: scalar.Int32(3),
Joe Tsaie1f8d502018-11-26 18:55:29 -080065 Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
66 Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
Joe Tsai009e0672018-11-27 18:45:07 -080067 TypeName: scalar.String(".test.C"),
68 OneofIndex: scalar.Int32(1),
Joe Tsai23ddbd12018-08-26 22:48:17 -070069 }, {
Joe Tsai009e0672018-11-27 18:45:07 -080070 Name: scalar.String("field_four"),
71 JsonName: scalar.String("Field4"),
72 Number: scalar.Int32(4),
Joe Tsaie1f8d502018-11-26 18:55:29 -080073 Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
74 Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
Joe Tsai15076352019-07-02 15:19:08 -070075 TypeName: scalar.String(".test.B.FieldFourEntry"),
Joe Tsai23ddbd12018-08-26 22:48:17 -070076 }, {
Joe Tsai009e0672018-11-27 18:45:07 -080077 Name: scalar.String("field_five"),
78 Number: scalar.Int32(5),
Joe Tsaie1f8d502018-11-26 18:55:29 -080079 Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
80 Type: descriptorpb.FieldDescriptorProto_Type(pref.Int32Kind).Enum(),
81 Options: &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
Joe Tsai23ddbd12018-08-26 22:48:17 -070082 }, {
Joe Tsai009e0672018-11-27 18:45:07 -080083 Name: scalar.String("field_six"),
84 Number: scalar.Int32(6),
Joe Tsaie1f8d502018-11-26 18:55:29 -080085 Label: descriptorpb.FieldDescriptorProto_Label(pref.Required).Enum(),
86 Type: descriptorpb.FieldDescriptorProto_Type(pref.BytesKind).Enum(),
Joe Tsai23ddbd12018-08-26 22:48:17 -070087 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -080088 OneofDecl: []*descriptorpb.OneofDescriptorProto{
Damien Neil204f1c02018-10-23 15:03:38 -070089 {
Joe Tsai009e0672018-11-27 18:45:07 -080090 Name: scalar.String("O1"),
Joe Tsaie1f8d502018-11-26 18:55:29 -080091 Options: &descriptorpb.OneofOptions{
92 UninterpretedOption: []*descriptorpb.UninterpretedOption{
Damien Neil204f1c02018-10-23 15:03:38 -070093 {StringValue: []byte("option")},
94 },
95 },
96 },
Joe Tsai009e0672018-11-27 18:45:07 -080097 {Name: scalar.String("O2")},
Joe Tsai23ddbd12018-08-26 22:48:17 -070098 },
Joe Tsaibce82b82018-12-06 09:39:03 -080099 ReservedName: []string{"fizz", "buzz"},
100 ReservedRange: []*descriptorpb.DescriptorProto_ReservedRange{
101 {Start: scalar.Int32(100), End: scalar.Int32(200)},
102 {Start: scalar.Int32(300), End: scalar.Int32(301)},
103 },
Joe Tsaie1f8d502018-11-26 18:55:29 -0800104 ExtensionRange: []*descriptorpb.DescriptorProto_ExtensionRange{
Joe Tsai009e0672018-11-27 18:45:07 -0800105 {Start: scalar.Int32(1000), End: scalar.Int32(2000)},
Joe Tsai381f04c2018-12-06 12:10:41 -0800106 {Start: scalar.Int32(3000), End: scalar.Int32(3001), Options: new(descriptorpb.ExtensionRangeOptions)},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700107 },
Joe Tsai15076352019-07-02 15:19:08 -0700108 NestedType: []*descriptorpb.DescriptorProto{{
109 Name: scalar.String("FieldFourEntry"),
110 Field: []*descriptorpb.FieldDescriptorProto{{
111 Name: scalar.String("key"),
112 Number: scalar.Int32(1),
113 Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
114 Type: descriptorpb.FieldDescriptorProto_Type(pref.StringKind).Enum(),
115 }, {
116 Name: scalar.String("value"),
117 Number: scalar.Int32(2),
118 Label: descriptorpb.FieldDescriptorProto_Label(pref.Optional).Enum(),
119 Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
120 TypeName: scalar.String(".test.B"),
121 }},
122 Options: &descriptorpb.MessageOptions{
123 MapEntry: scalar.Bool(true),
124 },
125 }},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700126 }, {
Joe Tsai009e0672018-11-27 18:45:07 -0800127 Name: scalar.String("C"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800128 NestedType: []*descriptorpb.DescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -0800129 Name: scalar.String("A"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800130 Field: []*descriptorpb.FieldDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -0800131 Name: scalar.String("F"),
132 Number: scalar.Int32(1),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800133 Label: descriptorpb.FieldDescriptorProto_Label(pref.Required).Enum(),
134 Type: descriptorpb.FieldDescriptorProto_Type(pref.BytesKind).Enum(),
Joe Tsai009e0672018-11-27 18:45:07 -0800135 DefaultValue: scalar.String(`dead\276\357`),
Joe Tsai23ddbd12018-08-26 22:48:17 -0700136 }},
137 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800138 EnumType: []*descriptorpb.EnumDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -0800139 Name: scalar.String("E1"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800140 Value: []*descriptorpb.EnumValueDescriptorProto{
Joe Tsai009e0672018-11-27 18:45:07 -0800141 {Name: scalar.String("FOO"), Number: scalar.Int32(0)},
142 {Name: scalar.String("BAR"), Number: scalar.Int32(1)},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700143 },
144 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800145 Extension: []*descriptorpb.FieldDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -0800146 Name: scalar.String("X"),
147 Number: scalar.Int32(1000),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800148 Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
149 Type: descriptorpb.FieldDescriptorProto_Type(pref.MessageKind).Enum(),
Joe Tsai009e0672018-11-27 18:45:07 -0800150 TypeName: scalar.String(".test.C"),
151 Extendee: scalar.String(".test.B"),
Joe Tsai23ddbd12018-08-26 22:48:17 -0700152 }},
153 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800154 EnumType: []*descriptorpb.EnumDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -0800155 Name: scalar.String("E1"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800156 Options: &descriptorpb.EnumOptions{Deprecated: scalar.Bool(true)},
157 Value: []*descriptorpb.EnumValueDescriptorProto{
Damien Neil204f1c02018-10-23 15:03:38 -0700158 {
Joe Tsai009e0672018-11-27 18:45:07 -0800159 Name: scalar.String("FOO"),
160 Number: scalar.Int32(0),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800161 Options: &descriptorpb.EnumValueOptions{Deprecated: scalar.Bool(true)},
Damien Neil204f1c02018-10-23 15:03:38 -0700162 },
Joe Tsai009e0672018-11-27 18:45:07 -0800163 {Name: scalar.String("BAR"), Number: scalar.Int32(1)},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700164 },
Joe Tsaibce82b82018-12-06 09:39:03 -0800165 ReservedName: []string{"FIZZ", "BUZZ"},
166 ReservedRange: []*descriptorpb.EnumDescriptorProto_EnumReservedRange{
167 {Start: scalar.Int32(10), End: scalar.Int32(19)},
168 {Start: scalar.Int32(30), End: scalar.Int32(30)},
169 },
Joe Tsai23ddbd12018-08-26 22:48:17 -0700170 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800171 Extension: []*descriptorpb.FieldDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -0800172 Name: scalar.String("X"),
173 Number: scalar.Int32(1000),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800174 Label: descriptorpb.FieldDescriptorProto_Label(pref.Repeated).Enum(),
Joe Tsai15076352019-07-02 15:19:08 -0700175 Type: descriptorpb.FieldDescriptorProto_Type(pref.EnumKind).Enum(),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800176 Options: &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
Joe Tsai15076352019-07-02 15:19:08 -0700177 TypeName: scalar.String(".test.E1"),
Joe Tsai009e0672018-11-27 18:45:07 -0800178 Extendee: scalar.String(".test.B"),
Joe Tsai23ddbd12018-08-26 22:48:17 -0700179 }},
Joe Tsaie1f8d502018-11-26 18:55:29 -0800180 Service: []*descriptorpb.ServiceDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -0800181 Name: scalar.String("S"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800182 Options: &descriptorpb.ServiceOptions{Deprecated: scalar.Bool(true)},
183 Method: []*descriptorpb.MethodDescriptorProto{{
Joe Tsai009e0672018-11-27 18:45:07 -0800184 Name: scalar.String("M"),
185 InputType: scalar.String(".test.A"),
186 OutputType: scalar.String(".test.C.A"),
187 ClientStreaming: scalar.Bool(true),
188 ServerStreaming: scalar.Bool(true),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800189 Options: &descriptorpb.MethodOptions{Deprecated: scalar.Bool(true)},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700190 }},
191 }},
192 }
Joe Tsaid8881392019-06-06 13:01:53 -0700193 fd1, err := pdesc.NewFile(f1, nil)
Joe Tsai23ddbd12018-08-26 22:48:17 -0700194 if err != nil {
Joe Tsaie1f8d502018-11-26 18:55:29 -0800195 t.Fatalf("protodesc.NewFile() error: %v", err)
Joe Tsai23ddbd12018-08-26 22:48:17 -0700196 }
197
Joe Tsaid8881392019-06-06 13:01:53 -0700198 b, err := proto.Marshal(f1)
199 if err != nil {
200 t.Fatalf("proto.Marshal() error: %v", err)
201 }
202 fd2 := filedesc.DescBuilder{RawDescriptor: b}.Build().File
203
Joe Tsai23ddbd12018-08-26 22:48:17 -0700204 tests := []struct {
205 name string
206 desc pref.FileDescriptor
207 }{
Joe Tsaid8881392019-06-06 13:01:53 -0700208 {"protodesc.NewFile", fd1},
209 {"filedesc.DescBuilder.Build", fd2},
Joe Tsai23ddbd12018-08-26 22:48:17 -0700210 }
211 for _, tt := range tests {
Joe Tsai17764982018-08-24 03:03:21 -0700212 tt := tt
Joe Tsai23ddbd12018-08-26 22:48:17 -0700213 t.Run(tt.name, func(t *testing.T) {
Joe Tsai17764982018-08-24 03:03:21 -0700214 // Run sub-tests in parallel to induce potential races.
215 for i := 0; i < 2; i++ {
216 t.Run("Accessors", func(t *testing.T) { t.Parallel(); testFileAccessors(t, tt.desc) })
Joe Tsaidd00a272018-09-13 12:50:58 -0700217 t.Run("Format", func(t *testing.T) { t.Parallel(); testFileFormat(t, tt.desc) })
Joe Tsai17764982018-08-24 03:03:21 -0700218 }
Joe Tsai23ddbd12018-08-26 22:48:17 -0700219 })
220 }
221}
222
223func testFileAccessors(t *testing.T, fd pref.FileDescriptor) {
Joe Tsaibfda0142018-08-10 13:58:07 -0700224 // Represent the descriptor as a map where each key is an accessor method
225 // and the value is either the wanted tail value or another accessor map.
226 type M = map[string]interface{}
227 want := M{
228 "Parent": nil,
Damien Neil3de06c02018-09-07 09:39:44 -0700229 "Index": 0,
Joe Tsaibfda0142018-08-10 13:58:07 -0700230 "Syntax": pref.Proto2,
231 "Name": pref.Name("test"),
232 "FullName": pref.FullName("test"),
233 "Path": "path/to/file.proto",
234 "Package": pref.FullName("test"),
235 "IsPlaceholder": false,
Joe Tsaie1f8d502018-11-26 18:55:29 -0800236 "Options": &descriptorpb.FileOptions{Deprecated: scalar.Bool(true)},
Joe Tsaibfda0142018-08-10 13:58:07 -0700237 "Messages": M{
238 "Len": 3,
239 "Get:0": M{
240 "Parent": M{"FullName": pref.FullName("test")},
Damien Neil3de06c02018-09-07 09:39:44 -0700241 "Index": 0,
Joe Tsaibfda0142018-08-10 13:58:07 -0700242 "Syntax": pref.Proto2,
243 "Name": pref.Name("A"),
244 "FullName": pref.FullName("test.A"),
245 "IsPlaceholder": false,
Joe Tsai15076352019-07-02 15:19:08 -0700246 "IsMapEntry": false,
Joe Tsaie1f8d502018-11-26 18:55:29 -0800247 "Options": &descriptorpb.MessageOptions{
Joe Tsai009e0672018-11-27 18:45:07 -0800248 Deprecated: scalar.Bool(true),
Damien Neil204f1c02018-10-23 15:03:38 -0700249 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700250 "Oneofs": M{"Len": 0},
251 "RequiredNumbers": M{"Len": 0},
252 "ExtensionRanges": M{"Len": 0},
253 "Messages": M{"Len": 0},
254 "Enums": M{"Len": 0},
255 "Extensions": M{"Len": 0},
256 },
257 "ByName:B": M{
Damien Neil3de06c02018-09-07 09:39:44 -0700258 "Name": pref.Name("B"),
259 "Index": 1,
Joe Tsaibfda0142018-08-10 13:58:07 -0700260 "Fields": M{
261 "Len": 6,
262 "ByJSONName:field_one": nil,
263 "ByJSONName:fieldOne": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700264 "Name": pref.Name("field_one"),
265 "Index": 0,
266 "JSONName": "fieldOne",
267 "Default": "hello, \"world!\"\n",
268 "ContainingOneof": M{"Name": pref.Name("O1"), "IsPlaceholder": false},
269 "ContainingMessage": M{"FullName": pref.FullName("test.B")},
Joe Tsaibfda0142018-08-10 13:58:07 -0700270 },
271 "ByJSONName:fieldTwo": nil,
272 "ByJSONName:Field2": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700273 "Name": pref.Name("field_two"),
274 "Index": 1,
275 "HasJSONName": true,
276 "JSONName": "Field2",
277 "Default": pref.EnumNumber(1),
278 "ContainingOneof": M{"Name": pref.Name("O2"), "IsPlaceholder": false},
Joe Tsaibfda0142018-08-10 13:58:07 -0700279 },
280 "ByName:fieldThree": nil,
281 "ByName:field_three": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700282 "IsExtension": false,
283 "IsMap": false,
284 "MapKey": nil,
285 "MapValue": nil,
286 "Message": M{"FullName": pref.FullName("test.C"), "IsPlaceholder": false},
287 "ContainingOneof": M{"Name": pref.Name("O2"), "IsPlaceholder": false},
288 "ContainingMessage": M{"FullName": pref.FullName("test.B")},
Joe Tsaibfda0142018-08-10 13:58:07 -0700289 },
290 "ByNumber:12": nil,
291 "ByNumber:4": M{
292 "Cardinality": pref.Repeated,
Joe Tsaiac31a352019-05-13 14:32:56 -0700293 "IsExtension": false,
294 "IsList": false,
Joe Tsaibfda0142018-08-10 13:58:07 -0700295 "IsMap": true,
Joe Tsaiac31a352019-05-13 14:32:56 -0700296 "MapKey": M{"Kind": pref.StringKind},
297 "MapValue": M{"Kind": pref.MessageKind, "Message": M{"FullName": pref.FullName("test.B")}},
Joe Tsaibfda0142018-08-10 13:58:07 -0700298 "Default": nil,
Joe Tsai15076352019-07-02 15:19:08 -0700299 "Message": M{"FullName": pref.FullName("test.B.FieldFourEntry"), "IsPlaceholder": false},
Joe Tsaibfda0142018-08-10 13:58:07 -0700300 },
301 "ByNumber:5": M{
302 "Cardinality": pref.Repeated,
303 "Kind": pref.Int32Kind,
304 "IsPacked": true,
Joe Tsaiac31a352019-05-13 14:32:56 -0700305 "IsList": true,
306 "IsMap": false,
Joe Tsai851185d2019-07-01 13:45:52 -0700307 "Default": nil,
Joe Tsaibfda0142018-08-10 13:58:07 -0700308 },
309 "ByNumber:6": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700310 "Cardinality": pref.Required,
311 "Default": []byte(nil),
312 "ContainingOneof": nil,
Joe Tsaibfda0142018-08-10 13:58:07 -0700313 },
314 },
315 "Oneofs": M{
316 "Len": 2,
317 "ByName:O0": nil,
318 "ByName:O1": M{
319 "FullName": pref.FullName("test.B.O1"),
Damien Neil3de06c02018-09-07 09:39:44 -0700320 "Index": 0,
Joe Tsaie1f8d502018-11-26 18:55:29 -0800321 "Options": &descriptorpb.OneofOptions{
322 UninterpretedOption: []*descriptorpb.UninterpretedOption{
Damien Neil204f1c02018-10-23 15:03:38 -0700323 {StringValue: []byte("option")},
324 },
325 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700326 "Fields": M{
327 "Len": 1,
328 "Get:0": M{"FullName": pref.FullName("test.B.field_one")},
329 },
330 },
331 "Get:1": M{
332 "FullName": pref.FullName("test.B.O2"),
Damien Neil3de06c02018-09-07 09:39:44 -0700333 "Index": 1,
Joe Tsaibfda0142018-08-10 13:58:07 -0700334 "Fields": M{
335 "Len": 2,
336 "ByName:field_two": M{"Name": pref.Name("field_two")},
337 "Get:1": M{"Name": pref.Name("field_three")},
338 },
339 },
340 },
Joe Tsaibce82b82018-12-06 09:39:03 -0800341 "ReservedNames": M{
342 "Len": 2,
343 "Get:0": pref.Name("fizz"),
344 "Has:buzz": true,
345 "Has:noexist": false,
346 },
347 "ReservedRanges": M{
348 "Len": 2,
349 "Get:0": [2]pref.FieldNumber{100, 200},
350 "Has:99": false,
351 "Has:100": true,
352 "Has:150": true,
353 "Has:199": true,
354 "Has:200": false,
355 "Has:300": true,
356 "Has:301": false,
357 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700358 "RequiredNumbers": M{
359 "Len": 1,
360 "Get:0": pref.FieldNumber(6),
361 "Has:1": false,
362 "Has:6": true,
363 },
364 "ExtensionRanges": M{
Joe Tsai17764982018-08-24 03:03:21 -0700365 "Len": 2,
Joe Tsaibfda0142018-08-10 13:58:07 -0700366 "Get:0": [2]pref.FieldNumber{1000, 2000},
367 "Has:999": false,
368 "Has:1000": true,
369 "Has:1500": true,
370 "Has:1999": true,
371 "Has:2000": false,
Joe Tsai17764982018-08-24 03:03:21 -0700372 "Has:3000": true,
Joe Tsaibce82b82018-12-06 09:39:03 -0800373 "Has:3001": false,
Joe Tsaibfda0142018-08-10 13:58:07 -0700374 },
Joe Tsai381f04c2018-12-06 12:10:41 -0800375 "ExtensionRangeOptions:0": (*descriptorpb.ExtensionRangeOptions)(nil),
376 "ExtensionRangeOptions:1": new(descriptorpb.ExtensionRangeOptions),
Joe Tsai15076352019-07-02 15:19:08 -0700377 "Messages": M{
378 "Get:0": M{
379 "Fields": M{
380 "Len": 2,
381 "ByNumber:1": M{
382 "Parent": M{"FullName": pref.FullName("test.B.FieldFourEntry")},
383 "Index": 0,
384 "Name": pref.Name("key"),
385 "FullName": pref.FullName("test.B.FieldFourEntry.key"),
386 "Number": pref.FieldNumber(1),
387 "Cardinality": pref.Optional,
388 "Kind": pref.StringKind,
389 "Options": (*descriptorpb.FieldOptions)(nil),
390 "HasJSONName": false,
391 "JSONName": "key",
392 "IsPacked": false,
393 "IsList": false,
394 "IsMap": false,
395 "IsExtension": false,
396 "IsWeak": false,
397 "Default": "",
398 "ContainingOneof": nil,
399 "ContainingMessage": M{"FullName": pref.FullName("test.B.FieldFourEntry")},
400 "Message": nil,
401 "Enum": nil,
402 },
403 "ByNumber:2": M{
404 "Parent": M{"FullName": pref.FullName("test.B.FieldFourEntry")},
405 "Index": 1,
406 "Name": pref.Name("value"),
407 "FullName": pref.FullName("test.B.FieldFourEntry.value"),
408 "Number": pref.FieldNumber(2),
409 "Cardinality": pref.Optional,
410 "Kind": pref.MessageKind,
411 "JSONName": "value",
412 "IsPacked": false,
413 "IsList": false,
414 "IsMap": false,
415 "IsExtension": false,
416 "IsWeak": false,
417 "Default": nil,
418 "ContainingOneof": nil,
419 "ContainingMessage": M{"FullName": pref.FullName("test.B.FieldFourEntry")},
420 "Message": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
421 "Enum": nil,
422 },
423 "ByNumber:3": nil,
424 },
425 },
426 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700427 },
428 "Get:2": M{
Damien Neil3de06c02018-09-07 09:39:44 -0700429 "Name": pref.Name("C"),
430 "Index": 2,
Joe Tsaibfda0142018-08-10 13:58:07 -0700431 "Messages": M{
432 "Len": 1,
433 "Get:0": M{"FullName": pref.FullName("test.C.A")},
434 },
435 "Enums": M{
436 "Len": 1,
437 "Get:0": M{"FullName": pref.FullName("test.C.E1")},
438 },
439 "Extensions": M{
440 "Len": 1,
441 "Get:0": M{"FullName": pref.FullName("test.C.X")},
442 },
443 },
444 },
445 "Enums": M{
446 "Len": 1,
447 "Get:0": M{
Damien Neil204f1c02018-10-23 15:03:38 -0700448 "Name": pref.Name("E1"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800449 "Options": &descriptorpb.EnumOptions{Deprecated: scalar.Bool(true)},
Joe Tsaibfda0142018-08-10 13:58:07 -0700450 "Values": M{
451 "Len": 2,
452 "ByName:Foo": nil,
Damien Neil204f1c02018-10-23 15:03:38 -0700453 "ByName:FOO": M{
454 "FullName": pref.FullName("test.FOO"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800455 "Options": &descriptorpb.EnumValueOptions{Deprecated: scalar.Bool(true)},
Damien Neil204f1c02018-10-23 15:03:38 -0700456 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700457 "ByNumber:2": nil,
458 "ByNumber:1": M{"FullName": pref.FullName("test.BAR")},
459 },
Joe Tsaibce82b82018-12-06 09:39:03 -0800460 "ReservedNames": M{
461 "Len": 2,
462 "Get:0": pref.Name("FIZZ"),
463 "Has:BUZZ": true,
464 "Has:NOEXIST": false,
465 },
466 "ReservedRanges": M{
467 "Len": 2,
468 "Get:0": [2]pref.EnumNumber{10, 19},
469 "Has:9": false,
470 "Has:10": true,
471 "Has:15": true,
472 "Has:19": true,
473 "Has:20": false,
474 "Has:30": true,
475 "Has:31": false,
476 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700477 },
478 },
479 "Extensions": M{
480 "Len": 1,
481 "ByName:X": M{
Joe Tsaiac31a352019-05-13 14:32:56 -0700482 "Name": pref.Name("X"),
483 "Number": pref.FieldNumber(1000),
484 "Cardinality": pref.Repeated,
Joe Tsai15076352019-07-02 15:19:08 -0700485 "Kind": pref.EnumKind,
Joe Tsaiac31a352019-05-13 14:32:56 -0700486 "IsExtension": true,
Joe Tsaid8881392019-06-06 13:01:53 -0700487 "IsPacked": true,
Joe Tsaiac31a352019-05-13 14:32:56 -0700488 "IsList": true,
489 "IsMap": false,
490 "MapKey": nil,
491 "MapValue": nil,
492 "ContainingOneof": nil,
493 "ContainingMessage": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
Joe Tsai15076352019-07-02 15:19:08 -0700494 "Enum": M{"FullName": pref.FullName("test.E1"), "IsPlaceholder": false},
Joe Tsaiac31a352019-05-13 14:32:56 -0700495 "Options": &descriptorpb.FieldOptions{Packed: scalar.Bool(true)},
Joe Tsaibfda0142018-08-10 13:58:07 -0700496 },
497 },
498 "Services": M{
499 "Len": 1,
500 "ByName:s": nil,
501 "ByName:S": M{
502 "Parent": M{"FullName": pref.FullName("test")},
503 "Name": pref.Name("S"),
504 "FullName": pref.FullName("test.S"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800505 "Options": &descriptorpb.ServiceOptions{Deprecated: scalar.Bool(true)},
Joe Tsaibfda0142018-08-10 13:58:07 -0700506 "Methods": M{
507 "Len": 1,
508 "Get:0": M{
509 "Parent": M{"FullName": pref.FullName("test.S")},
510 "Name": pref.Name("M"),
511 "FullName": pref.FullName("test.S.M"),
Joe Tsaid24bc722019-04-15 23:39:09 -0700512 "Input": M{"FullName": pref.FullName("test.A"), "IsPlaceholder": false},
513 "Output": M{"FullName": pref.FullName("test.C.A"), "IsPlaceholder": false},
Joe Tsaibfda0142018-08-10 13:58:07 -0700514 "IsStreamingClient": true,
515 "IsStreamingServer": true,
Joe Tsaie1f8d502018-11-26 18:55:29 -0800516 "Options": &descriptorpb.MethodOptions{Deprecated: scalar.Bool(true)},
Joe Tsaibfda0142018-08-10 13:58:07 -0700517 },
518 },
519 },
520 },
Joe Tsaibfda0142018-08-10 13:58:07 -0700521 }
Joe Tsai23ddbd12018-08-26 22:48:17 -0700522 checkAccessors(t, "", reflect.ValueOf(fd), want)
Joe Tsaibfda0142018-08-10 13:58:07 -0700523}
Joe Tsaibfda0142018-08-10 13:58:07 -0700524func checkAccessors(t *testing.T, p string, rv reflect.Value, want map[string]interface{}) {
Joe Tsaie1f8d502018-11-26 18:55:29 -0800525 p0 := p
526 defer func() {
527 if ex := recover(); ex != nil {
528 t.Errorf("panic at %v: %v", p, ex)
529 }
530 }()
531
Joe Tsaibfda0142018-08-10 13:58:07 -0700532 if rv.Interface() == nil {
533 t.Errorf("%v is nil, want non-nil", p)
534 return
535 }
536 for s, v := range want {
537 // Call the accessor method.
Joe Tsaie1f8d502018-11-26 18:55:29 -0800538 p = p0 + "." + s
Joe Tsaibfda0142018-08-10 13:58:07 -0700539 var rets []reflect.Value
540 if i := strings.IndexByte(s, ':'); i >= 0 {
541 // Accessor method takes in a single argument, which is encoded
542 // after the accessor name, separated by a ':' delimiter.
543 fnc := rv.MethodByName(s[:i])
544 arg := reflect.New(fnc.Type().In(0)).Elem()
545 s = s[i+len(":"):]
546 switch arg.Kind() {
547 case reflect.String:
548 arg.SetString(s)
549 case reflect.Int32, reflect.Int:
550 n, _ := strconv.ParseInt(s, 0, 64)
551 arg.SetInt(n)
552 }
553 rets = fnc.Call([]reflect.Value{arg})
554 } else {
555 rets = rv.MethodByName(s).Call(nil)
556 }
557
558 // Check that (val, ok) pattern is internally consistent.
559 if len(rets) == 2 {
560 if rets[0].IsNil() && rets[1].Bool() {
561 t.Errorf("%v = (nil, true), want (nil, false)", p)
562 }
563 if !rets[0].IsNil() && !rets[1].Bool() {
564 t.Errorf("%v = (non-nil, false), want (non-nil, true)", p)
565 }
566 }
567
568 // Check that the accessor output matches.
569 if want, ok := v.(map[string]interface{}); ok {
570 checkAccessors(t, p, rets[0], want)
Damien Neil204f1c02018-10-23 15:03:38 -0700571 continue
572 }
573
574 got := rets[0].Interface()
575 if pv, ok := got.(pref.Value); ok {
576 got = pv.Interface()
577 }
578
579 // Compare with proto.Equal if possible.
Joe Tsaid8881392019-06-06 13:01:53 -0700580 gotMsg, gotMsgOK := got.(proto.Message)
581 wantMsg, wantMsgOK := v.(proto.Message)
Damien Neil204f1c02018-10-23 15:03:38 -0700582 if gotMsgOK && wantMsgOK {
Joe Tsaid8881392019-06-06 13:01:53 -0700583 gotNil := reflect.ValueOf(gotMsg).IsNil()
584 wantNil := reflect.ValueOf(wantMsg).IsNil()
585 switch {
586 case !gotNil && wantNil:
587 t.Errorf("%v = non-nil, want nil", p)
588 case gotNil && !wantNil:
589 t.Errorf("%v = nil, want non-nil", p)
590 case !proto.Equal(gotMsg, wantMsg):
591 t.Errorf("%v = %v, want %v", p, gotMsg, wantMsg)
Joe Tsaibfda0142018-08-10 13:58:07 -0700592 }
Damien Neil204f1c02018-10-23 15:03:38 -0700593 continue
594 }
595
596 if want := v; !reflect.DeepEqual(got, want) {
Joe Tsai381f04c2018-12-06 12:10:41 -0800597 t.Errorf("%v = %T(%v), want %T(%v)", p, got, got, want, want)
Joe Tsaibfda0142018-08-10 13:58:07 -0700598 }
599 }
600}
601
Joe Tsaidd00a272018-09-13 12:50:58 -0700602func testFileFormat(t *testing.T, fd pref.FileDescriptor) {
Joe Tsai17764982018-08-24 03:03:21 -0700603 const want = `FileDescriptor{
604 Syntax: proto2
605 Path: "path/to/file.proto"
606 Package: test
607 Messages: [{
Joe Tsai15076352019-07-02 15:19:08 -0700608 Name: A
Joe Tsai17764982018-08-24 03:03:21 -0700609 }, {
610 Name: B
611 Fields: [{
612 Name: field_one
613 Number: 1
614 Cardinality: optional
615 Kind: string
616 JSONName: "fieldOne"
Damien Neile6fa22a2018-09-12 15:15:40 -0700617 HasDefault: true
Joe Tsai1dab2cb2018-09-28 13:39:07 -0700618 Default: "hello, \"world!\"\n"
Joe Tsaid24bc722019-04-15 23:39:09 -0700619 Oneof: O1
Joe Tsai17764982018-08-24 03:03:21 -0700620 }, {
621 Name: field_two
622 Number: 2
623 Cardinality: optional
624 Kind: enum
Joe Tsaibce82b82018-12-06 09:39:03 -0800625 HasJSONName: true
Joe Tsai17764982018-08-24 03:03:21 -0700626 JSONName: "Field2"
Damien Neile6fa22a2018-09-12 15:15:40 -0700627 HasDefault: true
Joe Tsai17764982018-08-24 03:03:21 -0700628 Default: 1
Joe Tsaid24bc722019-04-15 23:39:09 -0700629 Oneof: O2
630 Enum: test.E1
Joe Tsai17764982018-08-24 03:03:21 -0700631 }, {
632 Name: field_three
633 Number: 3
634 Cardinality: optional
635 Kind: message
636 JSONName: "fieldThree"
Joe Tsaid24bc722019-04-15 23:39:09 -0700637 Oneof: O2
638 Message: test.C
Joe Tsai17764982018-08-24 03:03:21 -0700639 }, {
640 Name: field_four
641 Number: 4
642 Cardinality: repeated
643 Kind: message
Joe Tsaibce82b82018-12-06 09:39:03 -0800644 HasJSONName: true
Joe Tsai17764982018-08-24 03:03:21 -0700645 JSONName: "Field4"
646 IsMap: true
Joe Tsaiac31a352019-05-13 14:32:56 -0700647 MapKey: string
648 MapValue: test.B
Joe Tsai17764982018-08-24 03:03:21 -0700649 }, {
650 Name: field_five
651 Number: 5
652 Cardinality: repeated
653 Kind: int32
654 JSONName: "fieldFive"
655 IsPacked: true
Joe Tsaiac31a352019-05-13 14:32:56 -0700656 IsList: true
Joe Tsai17764982018-08-24 03:03:21 -0700657 }, {
658 Name: field_six
659 Number: 6
660 Cardinality: required
661 Kind: bytes
662 JSONName: "fieldSix"
663 }]
664 Oneofs: [{
665 Name: O1
666 Fields: [field_one]
667 }, {
668 Name: O2
669 Fields: [field_two, field_three]
670 }]
Joe Tsaibce82b82018-12-06 09:39:03 -0800671 ReservedNames: [fizz, buzz]
672 ReservedRanges: [100:200, 300]
Joe Tsai17764982018-08-24 03:03:21 -0700673 RequiredNumbers: [6]
674 ExtensionRanges: [1000:2000, 3000]
Joe Tsai15076352019-07-02 15:19:08 -0700675 Messages: [{
676 Name: FieldFourEntry
677 IsMapEntry: true
678 Fields: [{
679 Name: key
680 Number: 1
681 Cardinality: optional
682 Kind: string
683 JSONName: "key"
684 }, {
685 Name: value
686 Number: 2
687 Cardinality: optional
688 Kind: message
689 JSONName: "value"
690 Message: test.B
691 }]
692 }]
Joe Tsai17764982018-08-24 03:03:21 -0700693 }, {
694 Name: C
695 Messages: [{
696 Name: A
697 Fields: [{
698 Name: F
699 Number: 1
700 Cardinality: required
701 Kind: bytes
702 JSONName: "F"
Damien Neile6fa22a2018-09-12 15:15:40 -0700703 HasDefault: true
Joe Tsai17764982018-08-24 03:03:21 -0700704 Default: "dead\xbe\xef"
705 }]
706 RequiredNumbers: [1]
707 }]
708 Enums: [{
709 Name: E1
710 Values: [
711 {Name: FOO}
712 {Name: BAR, Number: 1}
713 ]
714 }]
715 Extensions: [{
Joe Tsaid24bc722019-04-15 23:39:09 -0700716 Name: X
717 Number: 1000
718 Cardinality: repeated
719 Kind: message
Joe Tsaid8881392019-06-06 13:01:53 -0700720 JSONName: "X"
Joe Tsaiac31a352019-05-13 14:32:56 -0700721 IsExtension: true
722 IsList: true
Joe Tsaid24bc722019-04-15 23:39:09 -0700723 Extendee: test.B
724 Message: test.C
Joe Tsai17764982018-08-24 03:03:21 -0700725 }]
726 }]
727 Enums: [{
728 Name: E1
729 Values: [
730 {Name: FOO}
731 {Name: BAR, Number: 1}
732 ]
Joe Tsaibce82b82018-12-06 09:39:03 -0800733 ReservedNames: [FIZZ, BUZZ]
734 ReservedRanges: [10:20, 30]
Joe Tsai17764982018-08-24 03:03:21 -0700735 }]
736 Extensions: [{
Joe Tsaid24bc722019-04-15 23:39:09 -0700737 Name: X
738 Number: 1000
739 Cardinality: repeated
Joe Tsai15076352019-07-02 15:19:08 -0700740 Kind: enum
Joe Tsaid8881392019-06-06 13:01:53 -0700741 JSONName: "X"
742 IsPacked: true
Joe Tsaiac31a352019-05-13 14:32:56 -0700743 IsExtension: true
744 IsList: true
Joe Tsaid24bc722019-04-15 23:39:09 -0700745 Extendee: test.B
Joe Tsai15076352019-07-02 15:19:08 -0700746 Enum: test.E1
Joe Tsai17764982018-08-24 03:03:21 -0700747 }]
748 Services: [{
749 Name: S
750 Methods: [{
751 Name: M
Joe Tsaid24bc722019-04-15 23:39:09 -0700752 Input: test.A
753 Output: test.C.A
Joe Tsai17764982018-08-24 03:03:21 -0700754 IsStreamingClient: true
755 IsStreamingServer: true
756 }]
757 }]
758}`
Joe Tsaidd00a272018-09-13 12:50:58 -0700759 tests := []struct{ fmt, want string }{{"%v", compactMultiFormat(want)}, {"%+v", want}}
760 for _, tt := range tests {
761 got := fmt.Sprintf(tt.fmt, fd)
Joe Tsaiac31a352019-05-13 14:32:56 -0700762 if diff := cmp.Diff(got, tt.want); diff != "" {
763 t.Errorf("fmt.Sprintf(%q, fd) mismatch (-got +want):\n%s", tt.fmt, diff)
Joe Tsaidd00a272018-09-13 12:50:58 -0700764 }
Joe Tsai17764982018-08-24 03:03:21 -0700765 }
766}
767
Joe Tsaidd00a272018-09-13 12:50:58 -0700768// compactMultiFormat returns the single line form of a multi line output.
769func compactMultiFormat(s string) string {
770 var b []byte
771 for _, s := range strings.Split(s, "\n") {
772 s = strings.TrimSpace(s)
773 s = regexp.MustCompile(": +").ReplaceAllString(s, ": ")
774 prevWord := len(b) > 0 && b[len(b)-1] != '[' && b[len(b)-1] != '{'
775 nextWord := len(s) > 0 && s[0] != ']' && s[0] != '}'
776 if prevWord && nextWord {
777 b = append(b, ", "...)
778 }
779 b = append(b, s...)
780 }
781 return string(b)
782}