xref: /aosp_15_r20/external/golang-protobuf/internal/filedesc/desc_test.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
1*1c12ee1eSDan Willemsen// Copyright 2018 The Go Authors. All rights reserved.
2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style
3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file.
4*1c12ee1eSDan Willemsen
5*1c12ee1eSDan Willemsenpackage filedesc_test
6*1c12ee1eSDan Willemsen
7*1c12ee1eSDan Willemsenimport (
8*1c12ee1eSDan Willemsen	"fmt"
9*1c12ee1eSDan Willemsen	"reflect"
10*1c12ee1eSDan Willemsen	"regexp"
11*1c12ee1eSDan Willemsen	"strconv"
12*1c12ee1eSDan Willemsen	"strings"
13*1c12ee1eSDan Willemsen	"testing"
14*1c12ee1eSDan Willemsen
15*1c12ee1eSDan Willemsen	"github.com/google/go-cmp/cmp"
16*1c12ee1eSDan Willemsen
17*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/detrand"
18*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/filedesc"
19*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/proto"
20*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protodesc"
21*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoreflect"
22*1c12ee1eSDan Willemsen
23*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/types/descriptorpb"
24*1c12ee1eSDan Willemsen)
25*1c12ee1eSDan Willemsen
26*1c12ee1eSDan Willemsenfunc init() {
27*1c12ee1eSDan Willemsen	// Disable detrand to enable direct comparisons on outputs.
28*1c12ee1eSDan Willemsen	detrand.Disable()
29*1c12ee1eSDan Willemsen}
30*1c12ee1eSDan Willemsen
31*1c12ee1eSDan Willemsen// TODO: Test protodesc.NewFile with imported files.
32*1c12ee1eSDan Willemsen
33*1c12ee1eSDan Willemsenfunc TestFile(t *testing.T) {
34*1c12ee1eSDan Willemsen	f1 := &descriptorpb.FileDescriptorProto{
35*1c12ee1eSDan Willemsen		Syntax:  proto.String("proto2"),
36*1c12ee1eSDan Willemsen		Name:    proto.String("path/to/file.proto"),
37*1c12ee1eSDan Willemsen		Package: proto.String("test"),
38*1c12ee1eSDan Willemsen		Options: &descriptorpb.FileOptions{Deprecated: proto.Bool(true)},
39*1c12ee1eSDan Willemsen		MessageType: []*descriptorpb.DescriptorProto{{
40*1c12ee1eSDan Willemsen			Name: proto.String("A"),
41*1c12ee1eSDan Willemsen			Options: &descriptorpb.MessageOptions{
42*1c12ee1eSDan Willemsen				Deprecated: proto.Bool(true),
43*1c12ee1eSDan Willemsen			},
44*1c12ee1eSDan Willemsen		}, {
45*1c12ee1eSDan Willemsen			Name: proto.String("B"),
46*1c12ee1eSDan Willemsen			Field: []*descriptorpb.FieldDescriptorProto{{
47*1c12ee1eSDan Willemsen				Name:         proto.String("field_one"),
48*1c12ee1eSDan Willemsen				Number:       proto.Int32(1),
49*1c12ee1eSDan Willemsen				Label:        descriptorpb.FieldDescriptorProto_Label(protoreflect.Optional).Enum(),
50*1c12ee1eSDan Willemsen				Type:         descriptorpb.FieldDescriptorProto_Type(protoreflect.StringKind).Enum(),
51*1c12ee1eSDan Willemsen				DefaultValue: proto.String("hello, \"world!\"\n"),
52*1c12ee1eSDan Willemsen				OneofIndex:   proto.Int32(0),
53*1c12ee1eSDan Willemsen			}, {
54*1c12ee1eSDan Willemsen				Name:         proto.String("field_two"),
55*1c12ee1eSDan Willemsen				JsonName:     proto.String("Field2"),
56*1c12ee1eSDan Willemsen				Number:       proto.Int32(2),
57*1c12ee1eSDan Willemsen				Label:        descriptorpb.FieldDescriptorProto_Label(protoreflect.Optional).Enum(),
58*1c12ee1eSDan Willemsen				Type:         descriptorpb.FieldDescriptorProto_Type(protoreflect.EnumKind).Enum(),
59*1c12ee1eSDan Willemsen				DefaultValue: proto.String("BAR"),
60*1c12ee1eSDan Willemsen				TypeName:     proto.String(".test.E1"),
61*1c12ee1eSDan Willemsen				OneofIndex:   proto.Int32(1),
62*1c12ee1eSDan Willemsen			}, {
63*1c12ee1eSDan Willemsen				Name:       proto.String("field_three"),
64*1c12ee1eSDan Willemsen				Number:     proto.Int32(3),
65*1c12ee1eSDan Willemsen				Label:      descriptorpb.FieldDescriptorProto_Label(protoreflect.Optional).Enum(),
66*1c12ee1eSDan Willemsen				Type:       descriptorpb.FieldDescriptorProto_Type(protoreflect.MessageKind).Enum(),
67*1c12ee1eSDan Willemsen				TypeName:   proto.String(".test.C"),
68*1c12ee1eSDan Willemsen				OneofIndex: proto.Int32(1),
69*1c12ee1eSDan Willemsen			}, {
70*1c12ee1eSDan Willemsen				Name:     proto.String("field_four"),
71*1c12ee1eSDan Willemsen				JsonName: proto.String("Field4"),
72*1c12ee1eSDan Willemsen				Number:   proto.Int32(4),
73*1c12ee1eSDan Willemsen				Label:    descriptorpb.FieldDescriptorProto_Label(protoreflect.Repeated).Enum(),
74*1c12ee1eSDan Willemsen				Type:     descriptorpb.FieldDescriptorProto_Type(protoreflect.MessageKind).Enum(),
75*1c12ee1eSDan Willemsen				TypeName: proto.String(".test.B.FieldFourEntry"),
76*1c12ee1eSDan Willemsen			}, {
77*1c12ee1eSDan Willemsen				Name:    proto.String("field_five"),
78*1c12ee1eSDan Willemsen				Number:  proto.Int32(5),
79*1c12ee1eSDan Willemsen				Label:   descriptorpb.FieldDescriptorProto_Label(protoreflect.Repeated).Enum(),
80*1c12ee1eSDan Willemsen				Type:    descriptorpb.FieldDescriptorProto_Type(protoreflect.Int32Kind).Enum(),
81*1c12ee1eSDan Willemsen				Options: &descriptorpb.FieldOptions{Packed: proto.Bool(true)},
82*1c12ee1eSDan Willemsen			}, {
83*1c12ee1eSDan Willemsen				Name:   proto.String("field_six"),
84*1c12ee1eSDan Willemsen				Number: proto.Int32(6),
85*1c12ee1eSDan Willemsen				Label:  descriptorpb.FieldDescriptorProto_Label(protoreflect.Required).Enum(),
86*1c12ee1eSDan Willemsen				Type:   descriptorpb.FieldDescriptorProto_Type(protoreflect.BytesKind).Enum(),
87*1c12ee1eSDan Willemsen			}},
88*1c12ee1eSDan Willemsen			OneofDecl: []*descriptorpb.OneofDescriptorProto{
89*1c12ee1eSDan Willemsen				{
90*1c12ee1eSDan Willemsen					Name: proto.String("O1"),
91*1c12ee1eSDan Willemsen					Options: &descriptorpb.OneofOptions{
92*1c12ee1eSDan Willemsen						UninterpretedOption: []*descriptorpb.UninterpretedOption{
93*1c12ee1eSDan Willemsen							{StringValue: []byte("option")},
94*1c12ee1eSDan Willemsen						},
95*1c12ee1eSDan Willemsen					},
96*1c12ee1eSDan Willemsen				},
97*1c12ee1eSDan Willemsen				{Name: proto.String("O2")},
98*1c12ee1eSDan Willemsen			},
99*1c12ee1eSDan Willemsen			ReservedName: []string{"fizz", "buzz"},
100*1c12ee1eSDan Willemsen			ReservedRange: []*descriptorpb.DescriptorProto_ReservedRange{
101*1c12ee1eSDan Willemsen				{Start: proto.Int32(100), End: proto.Int32(200)},
102*1c12ee1eSDan Willemsen				{Start: proto.Int32(300), End: proto.Int32(301)},
103*1c12ee1eSDan Willemsen			},
104*1c12ee1eSDan Willemsen			ExtensionRange: []*descriptorpb.DescriptorProto_ExtensionRange{
105*1c12ee1eSDan Willemsen				{Start: proto.Int32(1000), End: proto.Int32(2000)},
106*1c12ee1eSDan Willemsen				{Start: proto.Int32(3000), End: proto.Int32(3001), Options: new(descriptorpb.ExtensionRangeOptions)},
107*1c12ee1eSDan Willemsen			},
108*1c12ee1eSDan Willemsen			NestedType: []*descriptorpb.DescriptorProto{{
109*1c12ee1eSDan Willemsen				Name: proto.String("FieldFourEntry"),
110*1c12ee1eSDan Willemsen				Field: []*descriptorpb.FieldDescriptorProto{{
111*1c12ee1eSDan Willemsen					Name:   proto.String("key"),
112*1c12ee1eSDan Willemsen					Number: proto.Int32(1),
113*1c12ee1eSDan Willemsen					Label:  descriptorpb.FieldDescriptorProto_Label(protoreflect.Optional).Enum(),
114*1c12ee1eSDan Willemsen					Type:   descriptorpb.FieldDescriptorProto_Type(protoreflect.StringKind).Enum(),
115*1c12ee1eSDan Willemsen				}, {
116*1c12ee1eSDan Willemsen					Name:     proto.String("value"),
117*1c12ee1eSDan Willemsen					Number:   proto.Int32(2),
118*1c12ee1eSDan Willemsen					Label:    descriptorpb.FieldDescriptorProto_Label(protoreflect.Optional).Enum(),
119*1c12ee1eSDan Willemsen					Type:     descriptorpb.FieldDescriptorProto_Type(protoreflect.MessageKind).Enum(),
120*1c12ee1eSDan Willemsen					TypeName: proto.String(".test.B"),
121*1c12ee1eSDan Willemsen				}},
122*1c12ee1eSDan Willemsen				Options: &descriptorpb.MessageOptions{
123*1c12ee1eSDan Willemsen					MapEntry: proto.Bool(true),
124*1c12ee1eSDan Willemsen				},
125*1c12ee1eSDan Willemsen			}},
126*1c12ee1eSDan Willemsen		}, {
127*1c12ee1eSDan Willemsen			Name: proto.String("C"),
128*1c12ee1eSDan Willemsen			NestedType: []*descriptorpb.DescriptorProto{{
129*1c12ee1eSDan Willemsen				Name: proto.String("A"),
130*1c12ee1eSDan Willemsen				Field: []*descriptorpb.FieldDescriptorProto{{
131*1c12ee1eSDan Willemsen					Name:         proto.String("F"),
132*1c12ee1eSDan Willemsen					Number:       proto.Int32(1),
133*1c12ee1eSDan Willemsen					Label:        descriptorpb.FieldDescriptorProto_Label(protoreflect.Required).Enum(),
134*1c12ee1eSDan Willemsen					Type:         descriptorpb.FieldDescriptorProto_Type(protoreflect.BytesKind).Enum(),
135*1c12ee1eSDan Willemsen					DefaultValue: proto.String(`dead\276\357`),
136*1c12ee1eSDan Willemsen				}},
137*1c12ee1eSDan Willemsen			}},
138*1c12ee1eSDan Willemsen			EnumType: []*descriptorpb.EnumDescriptorProto{{
139*1c12ee1eSDan Willemsen				Name: proto.String("E1"),
140*1c12ee1eSDan Willemsen				Value: []*descriptorpb.EnumValueDescriptorProto{
141*1c12ee1eSDan Willemsen					{Name: proto.String("FOO"), Number: proto.Int32(0)},
142*1c12ee1eSDan Willemsen					{Name: proto.String("BAR"), Number: proto.Int32(1)},
143*1c12ee1eSDan Willemsen				},
144*1c12ee1eSDan Willemsen			}},
145*1c12ee1eSDan Willemsen			Extension: []*descriptorpb.FieldDescriptorProto{{
146*1c12ee1eSDan Willemsen				Name:     proto.String("X"),
147*1c12ee1eSDan Willemsen				Number:   proto.Int32(1000),
148*1c12ee1eSDan Willemsen				Label:    descriptorpb.FieldDescriptorProto_Label(protoreflect.Repeated).Enum(),
149*1c12ee1eSDan Willemsen				Type:     descriptorpb.FieldDescriptorProto_Type(protoreflect.MessageKind).Enum(),
150*1c12ee1eSDan Willemsen				TypeName: proto.String(".test.C"),
151*1c12ee1eSDan Willemsen				Extendee: proto.String(".test.B"),
152*1c12ee1eSDan Willemsen			}},
153*1c12ee1eSDan Willemsen		}},
154*1c12ee1eSDan Willemsen		EnumType: []*descriptorpb.EnumDescriptorProto{{
155*1c12ee1eSDan Willemsen			Name:    proto.String("E1"),
156*1c12ee1eSDan Willemsen			Options: &descriptorpb.EnumOptions{Deprecated: proto.Bool(true)},
157*1c12ee1eSDan Willemsen			Value: []*descriptorpb.EnumValueDescriptorProto{
158*1c12ee1eSDan Willemsen				{
159*1c12ee1eSDan Willemsen					Name:    proto.String("FOO"),
160*1c12ee1eSDan Willemsen					Number:  proto.Int32(0),
161*1c12ee1eSDan Willemsen					Options: &descriptorpb.EnumValueOptions{Deprecated: proto.Bool(true)},
162*1c12ee1eSDan Willemsen				},
163*1c12ee1eSDan Willemsen				{Name: proto.String("BAR"), Number: proto.Int32(1)},
164*1c12ee1eSDan Willemsen			},
165*1c12ee1eSDan Willemsen			ReservedName: []string{"FIZZ", "BUZZ"},
166*1c12ee1eSDan Willemsen			ReservedRange: []*descriptorpb.EnumDescriptorProto_EnumReservedRange{
167*1c12ee1eSDan Willemsen				{Start: proto.Int32(10), End: proto.Int32(19)},
168*1c12ee1eSDan Willemsen				{Start: proto.Int32(30), End: proto.Int32(30)},
169*1c12ee1eSDan Willemsen			},
170*1c12ee1eSDan Willemsen		}},
171*1c12ee1eSDan Willemsen		Extension: []*descriptorpb.FieldDescriptorProto{{
172*1c12ee1eSDan Willemsen			Name:     proto.String("X"),
173*1c12ee1eSDan Willemsen			Number:   proto.Int32(1000),
174*1c12ee1eSDan Willemsen			Label:    descriptorpb.FieldDescriptorProto_Label(protoreflect.Repeated).Enum(),
175*1c12ee1eSDan Willemsen			Type:     descriptorpb.FieldDescriptorProto_Type(protoreflect.EnumKind).Enum(),
176*1c12ee1eSDan Willemsen			Options:  &descriptorpb.FieldOptions{Packed: proto.Bool(true)},
177*1c12ee1eSDan Willemsen			TypeName: proto.String(".test.E1"),
178*1c12ee1eSDan Willemsen			Extendee: proto.String(".test.B"),
179*1c12ee1eSDan Willemsen		}},
180*1c12ee1eSDan Willemsen		Service: []*descriptorpb.ServiceDescriptorProto{{
181*1c12ee1eSDan Willemsen			Name:    proto.String("S"),
182*1c12ee1eSDan Willemsen			Options: &descriptorpb.ServiceOptions{Deprecated: proto.Bool(true)},
183*1c12ee1eSDan Willemsen			Method: []*descriptorpb.MethodDescriptorProto{{
184*1c12ee1eSDan Willemsen				Name:            proto.String("M"),
185*1c12ee1eSDan Willemsen				InputType:       proto.String(".test.A"),
186*1c12ee1eSDan Willemsen				OutputType:      proto.String(".test.C.A"),
187*1c12ee1eSDan Willemsen				ClientStreaming: proto.Bool(true),
188*1c12ee1eSDan Willemsen				ServerStreaming: proto.Bool(true),
189*1c12ee1eSDan Willemsen				Options:         &descriptorpb.MethodOptions{Deprecated: proto.Bool(true)},
190*1c12ee1eSDan Willemsen			}},
191*1c12ee1eSDan Willemsen		}},
192*1c12ee1eSDan Willemsen	}
193*1c12ee1eSDan Willemsen	fd1, err := protodesc.NewFile(f1, nil)
194*1c12ee1eSDan Willemsen	if err != nil {
195*1c12ee1eSDan Willemsen		t.Fatalf("protodesc.NewFile() error: %v", err)
196*1c12ee1eSDan Willemsen	}
197*1c12ee1eSDan Willemsen
198*1c12ee1eSDan Willemsen	b, err := proto.Marshal(f1)
199*1c12ee1eSDan Willemsen	if err != nil {
200*1c12ee1eSDan Willemsen		t.Fatalf("proto.Marshal() error: %v", err)
201*1c12ee1eSDan Willemsen	}
202*1c12ee1eSDan Willemsen	fd2 := filedesc.Builder{RawDescriptor: b}.Build().File
203*1c12ee1eSDan Willemsen
204*1c12ee1eSDan Willemsen	tests := []struct {
205*1c12ee1eSDan Willemsen		name string
206*1c12ee1eSDan Willemsen		desc protoreflect.FileDescriptor
207*1c12ee1eSDan Willemsen	}{
208*1c12ee1eSDan Willemsen		{"protodesc.NewFile", fd1},
209*1c12ee1eSDan Willemsen		{"filedesc.Builder.Build", fd2},
210*1c12ee1eSDan Willemsen	}
211*1c12ee1eSDan Willemsen	for _, tt := range tests {
212*1c12ee1eSDan Willemsen		tt := tt
213*1c12ee1eSDan Willemsen		t.Run(tt.name, func(t *testing.T) {
214*1c12ee1eSDan Willemsen			// Run sub-tests in parallel to induce potential races.
215*1c12ee1eSDan Willemsen			for i := 0; i < 2; i++ {
216*1c12ee1eSDan Willemsen				t.Run("Accessors", func(t *testing.T) { t.Parallel(); testFileAccessors(t, tt.desc) })
217*1c12ee1eSDan Willemsen				t.Run("Format", func(t *testing.T) { t.Parallel(); testFileFormat(t, tt.desc) })
218*1c12ee1eSDan Willemsen			}
219*1c12ee1eSDan Willemsen		})
220*1c12ee1eSDan Willemsen	}
221*1c12ee1eSDan Willemsen}
222*1c12ee1eSDan Willemsen
223*1c12ee1eSDan Willemsenfunc testFileAccessors(t *testing.T, fd protoreflect.FileDescriptor) {
224*1c12ee1eSDan Willemsen	// Represent the descriptor as a map where each key is an accessor method
225*1c12ee1eSDan Willemsen	// and the value is either the wanted tail value or another accessor map.
226*1c12ee1eSDan Willemsen	type M = map[string]interface{}
227*1c12ee1eSDan Willemsen	want := M{
228*1c12ee1eSDan Willemsen		"Parent":        nil,
229*1c12ee1eSDan Willemsen		"Index":         0,
230*1c12ee1eSDan Willemsen		"Syntax":        protoreflect.Proto2,
231*1c12ee1eSDan Willemsen		"Name":          protoreflect.Name("test"),
232*1c12ee1eSDan Willemsen		"FullName":      protoreflect.FullName("test"),
233*1c12ee1eSDan Willemsen		"Path":          "path/to/file.proto",
234*1c12ee1eSDan Willemsen		"Package":       protoreflect.FullName("test"),
235*1c12ee1eSDan Willemsen		"IsPlaceholder": false,
236*1c12ee1eSDan Willemsen		"Options":       &descriptorpb.FileOptions{Deprecated: proto.Bool(true)},
237*1c12ee1eSDan Willemsen		"Messages": M{
238*1c12ee1eSDan Willemsen			"Len": 3,
239*1c12ee1eSDan Willemsen			"Get:0": M{
240*1c12ee1eSDan Willemsen				"Parent":        M{"FullName": protoreflect.FullName("test")},
241*1c12ee1eSDan Willemsen				"Index":         0,
242*1c12ee1eSDan Willemsen				"Syntax":        protoreflect.Proto2,
243*1c12ee1eSDan Willemsen				"Name":          protoreflect.Name("A"),
244*1c12ee1eSDan Willemsen				"FullName":      protoreflect.FullName("test.A"),
245*1c12ee1eSDan Willemsen				"IsPlaceholder": false,
246*1c12ee1eSDan Willemsen				"IsMapEntry":    false,
247*1c12ee1eSDan Willemsen				"Options": &descriptorpb.MessageOptions{
248*1c12ee1eSDan Willemsen					Deprecated: proto.Bool(true),
249*1c12ee1eSDan Willemsen				},
250*1c12ee1eSDan Willemsen				"Oneofs":          M{"Len": 0},
251*1c12ee1eSDan Willemsen				"RequiredNumbers": M{"Len": 0},
252*1c12ee1eSDan Willemsen				"ExtensionRanges": M{"Len": 0},
253*1c12ee1eSDan Willemsen				"Messages":        M{"Len": 0},
254*1c12ee1eSDan Willemsen				"Enums":           M{"Len": 0},
255*1c12ee1eSDan Willemsen				"Extensions":      M{"Len": 0},
256*1c12ee1eSDan Willemsen			},
257*1c12ee1eSDan Willemsen			"ByName:B": M{
258*1c12ee1eSDan Willemsen				"Name":  protoreflect.Name("B"),
259*1c12ee1eSDan Willemsen				"Index": 1,
260*1c12ee1eSDan Willemsen				"Fields": M{
261*1c12ee1eSDan Willemsen					"Len":                  6,
262*1c12ee1eSDan Willemsen					"ByJSONName:field_one": nil,
263*1c12ee1eSDan Willemsen					"ByJSONName:fieldOne": M{
264*1c12ee1eSDan Willemsen						"Name":              protoreflect.Name("field_one"),
265*1c12ee1eSDan Willemsen						"Index":             0,
266*1c12ee1eSDan Willemsen						"JSONName":          "fieldOne",
267*1c12ee1eSDan Willemsen						"Default":           "hello, \"world!\"\n",
268*1c12ee1eSDan Willemsen						"ContainingOneof":   M{"Name": protoreflect.Name("O1"), "IsPlaceholder": false},
269*1c12ee1eSDan Willemsen						"ContainingMessage": M{"FullName": protoreflect.FullName("test.B")},
270*1c12ee1eSDan Willemsen					},
271*1c12ee1eSDan Willemsen					"ByJSONName:fieldTwo": nil,
272*1c12ee1eSDan Willemsen					"ByJSONName:Field2": M{
273*1c12ee1eSDan Willemsen						"Name":            protoreflect.Name("field_two"),
274*1c12ee1eSDan Willemsen						"Index":           1,
275*1c12ee1eSDan Willemsen						"HasJSONName":     true,
276*1c12ee1eSDan Willemsen						"JSONName":        "Field2",
277*1c12ee1eSDan Willemsen						"Default":         protoreflect.EnumNumber(1),
278*1c12ee1eSDan Willemsen						"ContainingOneof": M{"Name": protoreflect.Name("O2"), "IsPlaceholder": false},
279*1c12ee1eSDan Willemsen					},
280*1c12ee1eSDan Willemsen					"ByName:fieldThree": nil,
281*1c12ee1eSDan Willemsen					"ByName:field_three": M{
282*1c12ee1eSDan Willemsen						"IsExtension":       false,
283*1c12ee1eSDan Willemsen						"IsMap":             false,
284*1c12ee1eSDan Willemsen						"MapKey":            nil,
285*1c12ee1eSDan Willemsen						"MapValue":          nil,
286*1c12ee1eSDan Willemsen						"Message":           M{"FullName": protoreflect.FullName("test.C"), "IsPlaceholder": false},
287*1c12ee1eSDan Willemsen						"ContainingOneof":   M{"Name": protoreflect.Name("O2"), "IsPlaceholder": false},
288*1c12ee1eSDan Willemsen						"ContainingMessage": M{"FullName": protoreflect.FullName("test.B")},
289*1c12ee1eSDan Willemsen					},
290*1c12ee1eSDan Willemsen					"ByNumber:12": nil,
291*1c12ee1eSDan Willemsen					"ByNumber:4": M{
292*1c12ee1eSDan Willemsen						"Cardinality": protoreflect.Repeated,
293*1c12ee1eSDan Willemsen						"IsExtension": false,
294*1c12ee1eSDan Willemsen						"IsList":      false,
295*1c12ee1eSDan Willemsen						"IsMap":       true,
296*1c12ee1eSDan Willemsen						"MapKey":      M{"Kind": protoreflect.StringKind},
297*1c12ee1eSDan Willemsen						"MapValue":    M{"Kind": protoreflect.MessageKind, "Message": M{"FullName": protoreflect.FullName("test.B")}},
298*1c12ee1eSDan Willemsen						"Default":     nil,
299*1c12ee1eSDan Willemsen						"Message":     M{"FullName": protoreflect.FullName("test.B.FieldFourEntry"), "IsPlaceholder": false},
300*1c12ee1eSDan Willemsen					},
301*1c12ee1eSDan Willemsen					"ByNumber:5": M{
302*1c12ee1eSDan Willemsen						"Cardinality": protoreflect.Repeated,
303*1c12ee1eSDan Willemsen						"Kind":        protoreflect.Int32Kind,
304*1c12ee1eSDan Willemsen						"IsPacked":    true,
305*1c12ee1eSDan Willemsen						"IsList":      true,
306*1c12ee1eSDan Willemsen						"IsMap":       false,
307*1c12ee1eSDan Willemsen						"Default":     nil,
308*1c12ee1eSDan Willemsen					},
309*1c12ee1eSDan Willemsen					"ByNumber:6": M{
310*1c12ee1eSDan Willemsen						"Cardinality":     protoreflect.Required,
311*1c12ee1eSDan Willemsen						"Default":         []byte(nil),
312*1c12ee1eSDan Willemsen						"ContainingOneof": nil,
313*1c12ee1eSDan Willemsen					},
314*1c12ee1eSDan Willemsen				},
315*1c12ee1eSDan Willemsen				"Oneofs": M{
316*1c12ee1eSDan Willemsen					"Len":       2,
317*1c12ee1eSDan Willemsen					"ByName:O0": nil,
318*1c12ee1eSDan Willemsen					"ByName:O1": M{
319*1c12ee1eSDan Willemsen						"FullName": protoreflect.FullName("test.B.O1"),
320*1c12ee1eSDan Willemsen						"Index":    0,
321*1c12ee1eSDan Willemsen						"Options": &descriptorpb.OneofOptions{
322*1c12ee1eSDan Willemsen							UninterpretedOption: []*descriptorpb.UninterpretedOption{
323*1c12ee1eSDan Willemsen								{StringValue: []byte("option")},
324*1c12ee1eSDan Willemsen							},
325*1c12ee1eSDan Willemsen						},
326*1c12ee1eSDan Willemsen						"Fields": M{
327*1c12ee1eSDan Willemsen							"Len":   1,
328*1c12ee1eSDan Willemsen							"Get:0": M{"FullName": protoreflect.FullName("test.B.field_one")},
329*1c12ee1eSDan Willemsen						},
330*1c12ee1eSDan Willemsen					},
331*1c12ee1eSDan Willemsen					"Get:1": M{
332*1c12ee1eSDan Willemsen						"FullName": protoreflect.FullName("test.B.O2"),
333*1c12ee1eSDan Willemsen						"Index":    1,
334*1c12ee1eSDan Willemsen						"Fields": M{
335*1c12ee1eSDan Willemsen							"Len":              2,
336*1c12ee1eSDan Willemsen							"ByName:field_two": M{"Name": protoreflect.Name("field_two")},
337*1c12ee1eSDan Willemsen							"Get:1":            M{"Name": protoreflect.Name("field_three")},
338*1c12ee1eSDan Willemsen						},
339*1c12ee1eSDan Willemsen					},
340*1c12ee1eSDan Willemsen				},
341*1c12ee1eSDan Willemsen				"ReservedNames": M{
342*1c12ee1eSDan Willemsen					"Len":         2,
343*1c12ee1eSDan Willemsen					"Get:0":       protoreflect.Name("fizz"),
344*1c12ee1eSDan Willemsen					"Has:buzz":    true,
345*1c12ee1eSDan Willemsen					"Has:noexist": false,
346*1c12ee1eSDan Willemsen				},
347*1c12ee1eSDan Willemsen				"ReservedRanges": M{
348*1c12ee1eSDan Willemsen					"Len":     2,
349*1c12ee1eSDan Willemsen					"Get:0":   [2]protoreflect.FieldNumber{100, 200},
350*1c12ee1eSDan Willemsen					"Has:99":  false,
351*1c12ee1eSDan Willemsen					"Has:100": true,
352*1c12ee1eSDan Willemsen					"Has:150": true,
353*1c12ee1eSDan Willemsen					"Has:199": true,
354*1c12ee1eSDan Willemsen					"Has:200": false,
355*1c12ee1eSDan Willemsen					"Has:300": true,
356*1c12ee1eSDan Willemsen					"Has:301": false,
357*1c12ee1eSDan Willemsen				},
358*1c12ee1eSDan Willemsen				"RequiredNumbers": M{
359*1c12ee1eSDan Willemsen					"Len":   1,
360*1c12ee1eSDan Willemsen					"Get:0": protoreflect.FieldNumber(6),
361*1c12ee1eSDan Willemsen					"Has:1": false,
362*1c12ee1eSDan Willemsen					"Has:6": true,
363*1c12ee1eSDan Willemsen				},
364*1c12ee1eSDan Willemsen				"ExtensionRanges": M{
365*1c12ee1eSDan Willemsen					"Len":      2,
366*1c12ee1eSDan Willemsen					"Get:0":    [2]protoreflect.FieldNumber{1000, 2000},
367*1c12ee1eSDan Willemsen					"Has:999":  false,
368*1c12ee1eSDan Willemsen					"Has:1000": true,
369*1c12ee1eSDan Willemsen					"Has:1500": true,
370*1c12ee1eSDan Willemsen					"Has:1999": true,
371*1c12ee1eSDan Willemsen					"Has:2000": false,
372*1c12ee1eSDan Willemsen					"Has:3000": true,
373*1c12ee1eSDan Willemsen					"Has:3001": false,
374*1c12ee1eSDan Willemsen				},
375*1c12ee1eSDan Willemsen				"ExtensionRangeOptions:0": (*descriptorpb.ExtensionRangeOptions)(nil),
376*1c12ee1eSDan Willemsen				"ExtensionRangeOptions:1": new(descriptorpb.ExtensionRangeOptions),
377*1c12ee1eSDan Willemsen				"Messages": M{
378*1c12ee1eSDan Willemsen					"Get:0": M{
379*1c12ee1eSDan Willemsen						"Fields": M{
380*1c12ee1eSDan Willemsen							"Len": 2,
381*1c12ee1eSDan Willemsen							"ByNumber:1": M{
382*1c12ee1eSDan Willemsen								"Parent":            M{"FullName": protoreflect.FullName("test.B.FieldFourEntry")},
383*1c12ee1eSDan Willemsen								"Index":             0,
384*1c12ee1eSDan Willemsen								"Name":              protoreflect.Name("key"),
385*1c12ee1eSDan Willemsen								"FullName":          protoreflect.FullName("test.B.FieldFourEntry.key"),
386*1c12ee1eSDan Willemsen								"Number":            protoreflect.FieldNumber(1),
387*1c12ee1eSDan Willemsen								"Cardinality":       protoreflect.Optional,
388*1c12ee1eSDan Willemsen								"Kind":              protoreflect.StringKind,
389*1c12ee1eSDan Willemsen								"Options":           (*descriptorpb.FieldOptions)(nil),
390*1c12ee1eSDan Willemsen								"HasJSONName":       false,
391*1c12ee1eSDan Willemsen								"JSONName":          "key",
392*1c12ee1eSDan Willemsen								"IsPacked":          false,
393*1c12ee1eSDan Willemsen								"IsList":            false,
394*1c12ee1eSDan Willemsen								"IsMap":             false,
395*1c12ee1eSDan Willemsen								"IsExtension":       false,
396*1c12ee1eSDan Willemsen								"IsWeak":            false,
397*1c12ee1eSDan Willemsen								"Default":           "",
398*1c12ee1eSDan Willemsen								"ContainingOneof":   nil,
399*1c12ee1eSDan Willemsen								"ContainingMessage": M{"FullName": protoreflect.FullName("test.B.FieldFourEntry")},
400*1c12ee1eSDan Willemsen								"Message":           nil,
401*1c12ee1eSDan Willemsen								"Enum":              nil,
402*1c12ee1eSDan Willemsen							},
403*1c12ee1eSDan Willemsen							"ByNumber:2": M{
404*1c12ee1eSDan Willemsen								"Parent":            M{"FullName": protoreflect.FullName("test.B.FieldFourEntry")},
405*1c12ee1eSDan Willemsen								"Index":             1,
406*1c12ee1eSDan Willemsen								"Name":              protoreflect.Name("value"),
407*1c12ee1eSDan Willemsen								"FullName":          protoreflect.FullName("test.B.FieldFourEntry.value"),
408*1c12ee1eSDan Willemsen								"Number":            protoreflect.FieldNumber(2),
409*1c12ee1eSDan Willemsen								"Cardinality":       protoreflect.Optional,
410*1c12ee1eSDan Willemsen								"Kind":              protoreflect.MessageKind,
411*1c12ee1eSDan Willemsen								"JSONName":          "value",
412*1c12ee1eSDan Willemsen								"IsPacked":          false,
413*1c12ee1eSDan Willemsen								"IsList":            false,
414*1c12ee1eSDan Willemsen								"IsMap":             false,
415*1c12ee1eSDan Willemsen								"IsExtension":       false,
416*1c12ee1eSDan Willemsen								"IsWeak":            false,
417*1c12ee1eSDan Willemsen								"Default":           nil,
418*1c12ee1eSDan Willemsen								"ContainingOneof":   nil,
419*1c12ee1eSDan Willemsen								"ContainingMessage": M{"FullName": protoreflect.FullName("test.B.FieldFourEntry")},
420*1c12ee1eSDan Willemsen								"Message":           M{"FullName": protoreflect.FullName("test.B"), "IsPlaceholder": false},
421*1c12ee1eSDan Willemsen								"Enum":              nil,
422*1c12ee1eSDan Willemsen							},
423*1c12ee1eSDan Willemsen							"ByNumber:3": nil,
424*1c12ee1eSDan Willemsen						},
425*1c12ee1eSDan Willemsen					},
426*1c12ee1eSDan Willemsen				},
427*1c12ee1eSDan Willemsen			},
428*1c12ee1eSDan Willemsen			"Get:2": M{
429*1c12ee1eSDan Willemsen				"Name":  protoreflect.Name("C"),
430*1c12ee1eSDan Willemsen				"Index": 2,
431*1c12ee1eSDan Willemsen				"Messages": M{
432*1c12ee1eSDan Willemsen					"Len":   1,
433*1c12ee1eSDan Willemsen					"Get:0": M{"FullName": protoreflect.FullName("test.C.A")},
434*1c12ee1eSDan Willemsen				},
435*1c12ee1eSDan Willemsen				"Enums": M{
436*1c12ee1eSDan Willemsen					"Len":   1,
437*1c12ee1eSDan Willemsen					"Get:0": M{"FullName": protoreflect.FullName("test.C.E1")},
438*1c12ee1eSDan Willemsen				},
439*1c12ee1eSDan Willemsen				"Extensions": M{
440*1c12ee1eSDan Willemsen					"Len":   1,
441*1c12ee1eSDan Willemsen					"Get:0": M{"FullName": protoreflect.FullName("test.C.X")},
442*1c12ee1eSDan Willemsen				},
443*1c12ee1eSDan Willemsen			},
444*1c12ee1eSDan Willemsen		},
445*1c12ee1eSDan Willemsen		"Enums": M{
446*1c12ee1eSDan Willemsen			"Len": 1,
447*1c12ee1eSDan Willemsen			"Get:0": M{
448*1c12ee1eSDan Willemsen				"Name":    protoreflect.Name("E1"),
449*1c12ee1eSDan Willemsen				"Options": &descriptorpb.EnumOptions{Deprecated: proto.Bool(true)},
450*1c12ee1eSDan Willemsen				"Values": M{
451*1c12ee1eSDan Willemsen					"Len":        2,
452*1c12ee1eSDan Willemsen					"ByName:Foo": nil,
453*1c12ee1eSDan Willemsen					"ByName:FOO": M{
454*1c12ee1eSDan Willemsen						"FullName": protoreflect.FullName("test.FOO"),
455*1c12ee1eSDan Willemsen						"Options":  &descriptorpb.EnumValueOptions{Deprecated: proto.Bool(true)},
456*1c12ee1eSDan Willemsen					},
457*1c12ee1eSDan Willemsen					"ByNumber:2": nil,
458*1c12ee1eSDan Willemsen					"ByNumber:1": M{"FullName": protoreflect.FullName("test.BAR")},
459*1c12ee1eSDan Willemsen				},
460*1c12ee1eSDan Willemsen				"ReservedNames": M{
461*1c12ee1eSDan Willemsen					"Len":         2,
462*1c12ee1eSDan Willemsen					"Get:0":       protoreflect.Name("FIZZ"),
463*1c12ee1eSDan Willemsen					"Has:BUZZ":    true,
464*1c12ee1eSDan Willemsen					"Has:NOEXIST": false,
465*1c12ee1eSDan Willemsen				},
466*1c12ee1eSDan Willemsen				"ReservedRanges": M{
467*1c12ee1eSDan Willemsen					"Len":    2,
468*1c12ee1eSDan Willemsen					"Get:0":  [2]protoreflect.EnumNumber{10, 19},
469*1c12ee1eSDan Willemsen					"Has:9":  false,
470*1c12ee1eSDan Willemsen					"Has:10": true,
471*1c12ee1eSDan Willemsen					"Has:15": true,
472*1c12ee1eSDan Willemsen					"Has:19": true,
473*1c12ee1eSDan Willemsen					"Has:20": false,
474*1c12ee1eSDan Willemsen					"Has:30": true,
475*1c12ee1eSDan Willemsen					"Has:31": false,
476*1c12ee1eSDan Willemsen				},
477*1c12ee1eSDan Willemsen			},
478*1c12ee1eSDan Willemsen		},
479*1c12ee1eSDan Willemsen		"Extensions": M{
480*1c12ee1eSDan Willemsen			"Len": 1,
481*1c12ee1eSDan Willemsen			"ByName:X": M{
482*1c12ee1eSDan Willemsen				"Name":              protoreflect.Name("X"),
483*1c12ee1eSDan Willemsen				"Number":            protoreflect.FieldNumber(1000),
484*1c12ee1eSDan Willemsen				"Cardinality":       protoreflect.Repeated,
485*1c12ee1eSDan Willemsen				"Kind":              protoreflect.EnumKind,
486*1c12ee1eSDan Willemsen				"IsExtension":       true,
487*1c12ee1eSDan Willemsen				"IsPacked":          true,
488*1c12ee1eSDan Willemsen				"IsList":            true,
489*1c12ee1eSDan Willemsen				"IsMap":             false,
490*1c12ee1eSDan Willemsen				"MapKey":            nil,
491*1c12ee1eSDan Willemsen				"MapValue":          nil,
492*1c12ee1eSDan Willemsen				"ContainingOneof":   nil,
493*1c12ee1eSDan Willemsen				"ContainingMessage": M{"FullName": protoreflect.FullName("test.B"), "IsPlaceholder": false},
494*1c12ee1eSDan Willemsen				"Enum":              M{"FullName": protoreflect.FullName("test.E1"), "IsPlaceholder": false},
495*1c12ee1eSDan Willemsen				"Options":           &descriptorpb.FieldOptions{Packed: proto.Bool(true)},
496*1c12ee1eSDan Willemsen			},
497*1c12ee1eSDan Willemsen		},
498*1c12ee1eSDan Willemsen		"Services": M{
499*1c12ee1eSDan Willemsen			"Len":      1,
500*1c12ee1eSDan Willemsen			"ByName:s": nil,
501*1c12ee1eSDan Willemsen			"ByName:S": M{
502*1c12ee1eSDan Willemsen				"Parent":   M{"FullName": protoreflect.FullName("test")},
503*1c12ee1eSDan Willemsen				"Name":     protoreflect.Name("S"),
504*1c12ee1eSDan Willemsen				"FullName": protoreflect.FullName("test.S"),
505*1c12ee1eSDan Willemsen				"Options":  &descriptorpb.ServiceOptions{Deprecated: proto.Bool(true)},
506*1c12ee1eSDan Willemsen				"Methods": M{
507*1c12ee1eSDan Willemsen					"Len": 1,
508*1c12ee1eSDan Willemsen					"Get:0": M{
509*1c12ee1eSDan Willemsen						"Parent":            M{"FullName": protoreflect.FullName("test.S")},
510*1c12ee1eSDan Willemsen						"Name":              protoreflect.Name("M"),
511*1c12ee1eSDan Willemsen						"FullName":          protoreflect.FullName("test.S.M"),
512*1c12ee1eSDan Willemsen						"Input":             M{"FullName": protoreflect.FullName("test.A"), "IsPlaceholder": false},
513*1c12ee1eSDan Willemsen						"Output":            M{"FullName": protoreflect.FullName("test.C.A"), "IsPlaceholder": false},
514*1c12ee1eSDan Willemsen						"IsStreamingClient": true,
515*1c12ee1eSDan Willemsen						"IsStreamingServer": true,
516*1c12ee1eSDan Willemsen						"Options":           &descriptorpb.MethodOptions{Deprecated: proto.Bool(true)},
517*1c12ee1eSDan Willemsen					},
518*1c12ee1eSDan Willemsen				},
519*1c12ee1eSDan Willemsen			},
520*1c12ee1eSDan Willemsen		},
521*1c12ee1eSDan Willemsen	}
522*1c12ee1eSDan Willemsen	checkAccessors(t, "", reflect.ValueOf(fd), want)
523*1c12ee1eSDan Willemsen}
524*1c12ee1eSDan Willemsenfunc checkAccessors(t *testing.T, p string, rv reflect.Value, want map[string]interface{}) {
525*1c12ee1eSDan Willemsen	p0 := p
526*1c12ee1eSDan Willemsen	defer func() {
527*1c12ee1eSDan Willemsen		if ex := recover(); ex != nil {
528*1c12ee1eSDan Willemsen			t.Errorf("panic at %v: %v", p, ex)
529*1c12ee1eSDan Willemsen		}
530*1c12ee1eSDan Willemsen	}()
531*1c12ee1eSDan Willemsen
532*1c12ee1eSDan Willemsen	if rv.Interface() == nil {
533*1c12ee1eSDan Willemsen		t.Errorf("%v is nil, want non-nil", p)
534*1c12ee1eSDan Willemsen		return
535*1c12ee1eSDan Willemsen	}
536*1c12ee1eSDan Willemsen	for s, v := range want {
537*1c12ee1eSDan Willemsen		// Call the accessor method.
538*1c12ee1eSDan Willemsen		p = p0 + "." + s
539*1c12ee1eSDan Willemsen		var rets []reflect.Value
540*1c12ee1eSDan Willemsen		if i := strings.IndexByte(s, ':'); i >= 0 {
541*1c12ee1eSDan Willemsen			// Accessor method takes in a single argument, which is encoded
542*1c12ee1eSDan Willemsen			// after the accessor name, separated by a ':' delimiter.
543*1c12ee1eSDan Willemsen			fnc := rv.MethodByName(s[:i])
544*1c12ee1eSDan Willemsen			arg := reflect.New(fnc.Type().In(0)).Elem()
545*1c12ee1eSDan Willemsen			s = s[i+len(":"):]
546*1c12ee1eSDan Willemsen			switch arg.Kind() {
547*1c12ee1eSDan Willemsen			case reflect.String:
548*1c12ee1eSDan Willemsen				arg.SetString(s)
549*1c12ee1eSDan Willemsen			case reflect.Int32, reflect.Int:
550*1c12ee1eSDan Willemsen				n, _ := strconv.ParseInt(s, 0, 64)
551*1c12ee1eSDan Willemsen				arg.SetInt(n)
552*1c12ee1eSDan Willemsen			}
553*1c12ee1eSDan Willemsen			rets = fnc.Call([]reflect.Value{arg})
554*1c12ee1eSDan Willemsen		} else {
555*1c12ee1eSDan Willemsen			rets = rv.MethodByName(s).Call(nil)
556*1c12ee1eSDan Willemsen		}
557*1c12ee1eSDan Willemsen
558*1c12ee1eSDan Willemsen		// Check that (val, ok) pattern is internally consistent.
559*1c12ee1eSDan Willemsen		if len(rets) == 2 {
560*1c12ee1eSDan Willemsen			if rets[0].IsNil() && rets[1].Bool() {
561*1c12ee1eSDan Willemsen				t.Errorf("%v = (nil, true), want (nil, false)", p)
562*1c12ee1eSDan Willemsen			}
563*1c12ee1eSDan Willemsen			if !rets[0].IsNil() && !rets[1].Bool() {
564*1c12ee1eSDan Willemsen				t.Errorf("%v = (non-nil, false), want (non-nil, true)", p)
565*1c12ee1eSDan Willemsen			}
566*1c12ee1eSDan Willemsen		}
567*1c12ee1eSDan Willemsen
568*1c12ee1eSDan Willemsen		// Check that the accessor output matches.
569*1c12ee1eSDan Willemsen		if want, ok := v.(map[string]interface{}); ok {
570*1c12ee1eSDan Willemsen			checkAccessors(t, p, rets[0], want)
571*1c12ee1eSDan Willemsen			continue
572*1c12ee1eSDan Willemsen		}
573*1c12ee1eSDan Willemsen
574*1c12ee1eSDan Willemsen		got := rets[0].Interface()
575*1c12ee1eSDan Willemsen		if pv, ok := got.(protoreflect.Value); ok {
576*1c12ee1eSDan Willemsen			got = pv.Interface()
577*1c12ee1eSDan Willemsen		}
578*1c12ee1eSDan Willemsen
579*1c12ee1eSDan Willemsen		// Compare with proto.Equal if possible.
580*1c12ee1eSDan Willemsen		gotMsg, gotMsgOK := got.(proto.Message)
581*1c12ee1eSDan Willemsen		wantMsg, wantMsgOK := v.(proto.Message)
582*1c12ee1eSDan Willemsen		if gotMsgOK && wantMsgOK {
583*1c12ee1eSDan Willemsen			gotNil := reflect.ValueOf(gotMsg).IsNil()
584*1c12ee1eSDan Willemsen			wantNil := reflect.ValueOf(wantMsg).IsNil()
585*1c12ee1eSDan Willemsen			switch {
586*1c12ee1eSDan Willemsen			case !gotNil && wantNil:
587*1c12ee1eSDan Willemsen				t.Errorf("%v = non-nil, want nil", p)
588*1c12ee1eSDan Willemsen			case gotNil && !wantNil:
589*1c12ee1eSDan Willemsen				t.Errorf("%v = nil, want non-nil", p)
590*1c12ee1eSDan Willemsen			case !proto.Equal(gotMsg, wantMsg):
591*1c12ee1eSDan Willemsen				t.Errorf("%v = %v, want %v", p, gotMsg, wantMsg)
592*1c12ee1eSDan Willemsen			}
593*1c12ee1eSDan Willemsen			continue
594*1c12ee1eSDan Willemsen		}
595*1c12ee1eSDan Willemsen
596*1c12ee1eSDan Willemsen		if want := v; !reflect.DeepEqual(got, want) {
597*1c12ee1eSDan Willemsen			t.Errorf("%v = %T(%v), want %T(%v)", p, got, got, want, want)
598*1c12ee1eSDan Willemsen		}
599*1c12ee1eSDan Willemsen	}
600*1c12ee1eSDan Willemsen}
601*1c12ee1eSDan Willemsen
602*1c12ee1eSDan Willemsenfunc testFileFormat(t *testing.T, fd protoreflect.FileDescriptor) {
603*1c12ee1eSDan Willemsen	const wantFileDescriptor = `FileDescriptor{
604*1c12ee1eSDan Willemsen	Syntax:  proto2
605*1c12ee1eSDan Willemsen	Path:    "path/to/file.proto"
606*1c12ee1eSDan Willemsen	Package: test
607*1c12ee1eSDan Willemsen	Messages: [{
608*1c12ee1eSDan Willemsen		Name: A
609*1c12ee1eSDan Willemsen	}, {
610*1c12ee1eSDan Willemsen		Name: B
611*1c12ee1eSDan Willemsen		Fields: [{
612*1c12ee1eSDan Willemsen			Name:        field_one
613*1c12ee1eSDan Willemsen			Number:      1
614*1c12ee1eSDan Willemsen			Cardinality: optional
615*1c12ee1eSDan Willemsen			Kind:        string
616*1c12ee1eSDan Willemsen			JSONName:    "fieldOne"
617*1c12ee1eSDan Willemsen			HasPresence: true
618*1c12ee1eSDan Willemsen			HasDefault:  true
619*1c12ee1eSDan Willemsen			Default:     "hello, \"world!\"\n"
620*1c12ee1eSDan Willemsen			Oneof:       O1
621*1c12ee1eSDan Willemsen		}, {
622*1c12ee1eSDan Willemsen			Name:        field_two
623*1c12ee1eSDan Willemsen			Number:      2
624*1c12ee1eSDan Willemsen			Cardinality: optional
625*1c12ee1eSDan Willemsen			Kind:        enum
626*1c12ee1eSDan Willemsen			HasJSONName: true
627*1c12ee1eSDan Willemsen			JSONName:    "Field2"
628*1c12ee1eSDan Willemsen			HasPresence: true
629*1c12ee1eSDan Willemsen			HasDefault:  true
630*1c12ee1eSDan Willemsen			Default:     1
631*1c12ee1eSDan Willemsen			Oneof:       O2
632*1c12ee1eSDan Willemsen			Enum:        test.E1
633*1c12ee1eSDan Willemsen		}, {
634*1c12ee1eSDan Willemsen			Name:        field_three
635*1c12ee1eSDan Willemsen			Number:      3
636*1c12ee1eSDan Willemsen			Cardinality: optional
637*1c12ee1eSDan Willemsen			Kind:        message
638*1c12ee1eSDan Willemsen			JSONName:    "fieldThree"
639*1c12ee1eSDan Willemsen			HasPresence: true
640*1c12ee1eSDan Willemsen			Oneof:       O2
641*1c12ee1eSDan Willemsen			Message:     test.C
642*1c12ee1eSDan Willemsen		}, {
643*1c12ee1eSDan Willemsen			Name:        field_four
644*1c12ee1eSDan Willemsen			Number:      4
645*1c12ee1eSDan Willemsen			Cardinality: repeated
646*1c12ee1eSDan Willemsen			Kind:        message
647*1c12ee1eSDan Willemsen			HasJSONName: true
648*1c12ee1eSDan Willemsen			JSONName:    "Field4"
649*1c12ee1eSDan Willemsen			IsMap:       true
650*1c12ee1eSDan Willemsen			MapKey:      string
651*1c12ee1eSDan Willemsen			MapValue:    test.B
652*1c12ee1eSDan Willemsen		}, {
653*1c12ee1eSDan Willemsen			Name:        field_five
654*1c12ee1eSDan Willemsen			Number:      5
655*1c12ee1eSDan Willemsen			Cardinality: repeated
656*1c12ee1eSDan Willemsen			Kind:        int32
657*1c12ee1eSDan Willemsen			JSONName:    "fieldFive"
658*1c12ee1eSDan Willemsen			IsPacked:    true
659*1c12ee1eSDan Willemsen			IsList:      true
660*1c12ee1eSDan Willemsen		}, {
661*1c12ee1eSDan Willemsen			Name:        field_six
662*1c12ee1eSDan Willemsen			Number:      6
663*1c12ee1eSDan Willemsen			Cardinality: required
664*1c12ee1eSDan Willemsen			Kind:        bytes
665*1c12ee1eSDan Willemsen			JSONName:    "fieldSix"
666*1c12ee1eSDan Willemsen			HasPresence: true
667*1c12ee1eSDan Willemsen		}]
668*1c12ee1eSDan Willemsen		Oneofs: [{
669*1c12ee1eSDan Willemsen			Name:   O1
670*1c12ee1eSDan Willemsen			Fields: [field_one]
671*1c12ee1eSDan Willemsen		}, {
672*1c12ee1eSDan Willemsen			Name:   O2
673*1c12ee1eSDan Willemsen			Fields: [field_two, field_three]
674*1c12ee1eSDan Willemsen		}]
675*1c12ee1eSDan Willemsen		ReservedNames:   [fizz, buzz]
676*1c12ee1eSDan Willemsen		ReservedRanges:  [100:200, 300]
677*1c12ee1eSDan Willemsen		RequiredNumbers: [6]
678*1c12ee1eSDan Willemsen		ExtensionRanges: [1000:2000, 3000]
679*1c12ee1eSDan Willemsen		Messages: [{
680*1c12ee1eSDan Willemsen			Name:       FieldFourEntry
681*1c12ee1eSDan Willemsen			IsMapEntry: true
682*1c12ee1eSDan Willemsen			Fields: [{
683*1c12ee1eSDan Willemsen				Name:        key
684*1c12ee1eSDan Willemsen				Number:      1
685*1c12ee1eSDan Willemsen				Cardinality: optional
686*1c12ee1eSDan Willemsen				Kind:        string
687*1c12ee1eSDan Willemsen				JSONName:    "key"
688*1c12ee1eSDan Willemsen				HasPresence: true
689*1c12ee1eSDan Willemsen			}, {
690*1c12ee1eSDan Willemsen				Name:        value
691*1c12ee1eSDan Willemsen				Number:      2
692*1c12ee1eSDan Willemsen				Cardinality: optional
693*1c12ee1eSDan Willemsen				Kind:        message
694*1c12ee1eSDan Willemsen				JSONName:    "value"
695*1c12ee1eSDan Willemsen				HasPresence: true
696*1c12ee1eSDan Willemsen				Message:     test.B
697*1c12ee1eSDan Willemsen			}]
698*1c12ee1eSDan Willemsen		}]
699*1c12ee1eSDan Willemsen	}, {
700*1c12ee1eSDan Willemsen		Name: C
701*1c12ee1eSDan Willemsen		Messages: [{
702*1c12ee1eSDan Willemsen			Name: A
703*1c12ee1eSDan Willemsen			Fields: [{
704*1c12ee1eSDan Willemsen				Name:        F
705*1c12ee1eSDan Willemsen				Number:      1
706*1c12ee1eSDan Willemsen				Cardinality: required
707*1c12ee1eSDan Willemsen				Kind:        bytes
708*1c12ee1eSDan Willemsen				JSONName:    "F"
709*1c12ee1eSDan Willemsen				HasPresence: true
710*1c12ee1eSDan Willemsen				HasDefault:  true
711*1c12ee1eSDan Willemsen				Default:     "dead\xbe\xef"
712*1c12ee1eSDan Willemsen			}]
713*1c12ee1eSDan Willemsen			RequiredNumbers: [1]
714*1c12ee1eSDan Willemsen		}]
715*1c12ee1eSDan Willemsen		Enums: [{
716*1c12ee1eSDan Willemsen			Name: E1
717*1c12ee1eSDan Willemsen			Values: [
718*1c12ee1eSDan Willemsen				{Name: FOO}
719*1c12ee1eSDan Willemsen				{Name: BAR, Number: 1}
720*1c12ee1eSDan Willemsen			]
721*1c12ee1eSDan Willemsen		}]
722*1c12ee1eSDan Willemsen		Extensions: [{
723*1c12ee1eSDan Willemsen			Name:        X
724*1c12ee1eSDan Willemsen			Number:      1000
725*1c12ee1eSDan Willemsen			Cardinality: repeated
726*1c12ee1eSDan Willemsen			Kind:        message
727*1c12ee1eSDan Willemsen			JSONName:    "[test.C.X]"
728*1c12ee1eSDan Willemsen			IsExtension: true
729*1c12ee1eSDan Willemsen			IsList:      true
730*1c12ee1eSDan Willemsen			Extendee:    test.B
731*1c12ee1eSDan Willemsen			Message:     test.C
732*1c12ee1eSDan Willemsen		}]
733*1c12ee1eSDan Willemsen	}]
734*1c12ee1eSDan Willemsen	Enums: [{
735*1c12ee1eSDan Willemsen		Name: E1
736*1c12ee1eSDan Willemsen		Values: [
737*1c12ee1eSDan Willemsen			{Name: FOO}
738*1c12ee1eSDan Willemsen			{Name: BAR, Number: 1}
739*1c12ee1eSDan Willemsen		]
740*1c12ee1eSDan Willemsen		ReservedNames:  [FIZZ, BUZZ]
741*1c12ee1eSDan Willemsen		ReservedRanges: [10:20, 30]
742*1c12ee1eSDan Willemsen	}]
743*1c12ee1eSDan Willemsen	Extensions: [{
744*1c12ee1eSDan Willemsen		Name:        X
745*1c12ee1eSDan Willemsen		Number:      1000
746*1c12ee1eSDan Willemsen		Cardinality: repeated
747*1c12ee1eSDan Willemsen		Kind:        enum
748*1c12ee1eSDan Willemsen		JSONName:    "[test.X]"
749*1c12ee1eSDan Willemsen		IsExtension: true
750*1c12ee1eSDan Willemsen		IsPacked:    true
751*1c12ee1eSDan Willemsen		IsList:      true
752*1c12ee1eSDan Willemsen		Extendee:    test.B
753*1c12ee1eSDan Willemsen		Enum:        test.E1
754*1c12ee1eSDan Willemsen	}]
755*1c12ee1eSDan Willemsen	Services: [{
756*1c12ee1eSDan Willemsen		Name: S
757*1c12ee1eSDan Willemsen		Methods: [{
758*1c12ee1eSDan Willemsen			Name:              M
759*1c12ee1eSDan Willemsen			Input:             test.A
760*1c12ee1eSDan Willemsen			Output:            test.C.A
761*1c12ee1eSDan Willemsen			IsStreamingClient: true
762*1c12ee1eSDan Willemsen			IsStreamingServer: true
763*1c12ee1eSDan Willemsen		}]
764*1c12ee1eSDan Willemsen	}]
765*1c12ee1eSDan Willemsen}`
766*1c12ee1eSDan Willemsen
767*1c12ee1eSDan Willemsen	const wantEnums = `Enums{{
768*1c12ee1eSDan Willemsen	Name: E1
769*1c12ee1eSDan Willemsen	Values: [
770*1c12ee1eSDan Willemsen		{Name: FOO}
771*1c12ee1eSDan Willemsen		{Name: BAR, Number: 1}
772*1c12ee1eSDan Willemsen	]
773*1c12ee1eSDan Willemsen	ReservedNames:  [FIZZ, BUZZ]
774*1c12ee1eSDan Willemsen	ReservedRanges: [10:20, 30]
775*1c12ee1eSDan Willemsen}}`
776*1c12ee1eSDan Willemsen
777*1c12ee1eSDan Willemsen	const wantExtensions = `Extensions{{
778*1c12ee1eSDan Willemsen	Name:        X
779*1c12ee1eSDan Willemsen	Number:      1000
780*1c12ee1eSDan Willemsen	Cardinality: repeated
781*1c12ee1eSDan Willemsen	Kind:        enum
782*1c12ee1eSDan Willemsen	JSONName:    "[test.X]"
783*1c12ee1eSDan Willemsen	IsExtension: true
784*1c12ee1eSDan Willemsen	IsPacked:    true
785*1c12ee1eSDan Willemsen	IsList:      true
786*1c12ee1eSDan Willemsen	Extendee:    test.B
787*1c12ee1eSDan Willemsen	Enum:        test.E1
788*1c12ee1eSDan Willemsen}}`
789*1c12ee1eSDan Willemsen
790*1c12ee1eSDan Willemsen	const wantImports = `FileImports{}`
791*1c12ee1eSDan Willemsen
792*1c12ee1eSDan Willemsen	const wantReservedNames = "Names{fizz, buzz}"
793*1c12ee1eSDan Willemsen
794*1c12ee1eSDan Willemsen	const wantReservedRanges = "FieldRanges{100:200, 300}"
795*1c12ee1eSDan Willemsen
796*1c12ee1eSDan Willemsen	const wantServices = `Services{{
797*1c12ee1eSDan Willemsen	Name: S
798*1c12ee1eSDan Willemsen	Methods: [{
799*1c12ee1eSDan Willemsen		Name:              M
800*1c12ee1eSDan Willemsen		Input:             test.A
801*1c12ee1eSDan Willemsen		Output:            test.C.A
802*1c12ee1eSDan Willemsen		IsStreamingClient: true
803*1c12ee1eSDan Willemsen		IsStreamingServer: true
804*1c12ee1eSDan Willemsen	}]
805*1c12ee1eSDan Willemsen}}`
806*1c12ee1eSDan Willemsen
807*1c12ee1eSDan Willemsen	tests := []struct {
808*1c12ee1eSDan Willemsen		path string
809*1c12ee1eSDan Willemsen		fmt  string
810*1c12ee1eSDan Willemsen		want string
811*1c12ee1eSDan Willemsen		val  interface{}
812*1c12ee1eSDan Willemsen	}{
813*1c12ee1eSDan Willemsen		{"fd", "%v", compactMultiFormat(wantFileDescriptor), fd},
814*1c12ee1eSDan Willemsen		{"fd", "%+v", wantFileDescriptor, fd},
815*1c12ee1eSDan Willemsen		{"fd.Enums()", "%v", compactMultiFormat(wantEnums), fd.Enums()},
816*1c12ee1eSDan Willemsen		{"fd.Enums()", "%+v", wantEnums, fd.Enums()},
817*1c12ee1eSDan Willemsen		{"fd.Extensions()", "%v", compactMultiFormat(wantExtensions), fd.Extensions()},
818*1c12ee1eSDan Willemsen		{"fd.Extensions()", "%+v", wantExtensions, fd.Extensions()},
819*1c12ee1eSDan Willemsen		{"fd.Imports()", "%v", compactMultiFormat(wantImports), fd.Imports()},
820*1c12ee1eSDan Willemsen		{"fd.Imports()", "%+v", wantImports, fd.Imports()},
821*1c12ee1eSDan Willemsen		{"fd.Messages(B).ReservedNames()", "%v", compactMultiFormat(wantReservedNames), fd.Messages().ByName("B").ReservedNames()},
822*1c12ee1eSDan Willemsen		{"fd.Messages(B).ReservedNames()", "%+v", wantReservedNames, fd.Messages().ByName("B").ReservedNames()},
823*1c12ee1eSDan Willemsen		{"fd.Messages(B).ReservedRanges()", "%v", compactMultiFormat(wantReservedRanges), fd.Messages().ByName("B").ReservedRanges()},
824*1c12ee1eSDan Willemsen		{"fd.Messages(B).ReservedRanges()", "%+v", wantReservedRanges, fd.Messages().ByName("B").ReservedRanges()},
825*1c12ee1eSDan Willemsen		{"fd.Services()", "%v", compactMultiFormat(wantServices), fd.Services()},
826*1c12ee1eSDan Willemsen		{"fd.Services()", "%+v", wantServices, fd.Services()},
827*1c12ee1eSDan Willemsen	}
828*1c12ee1eSDan Willemsen	for _, tt := range tests {
829*1c12ee1eSDan Willemsen		got := fmt.Sprintf(tt.fmt, tt.val)
830*1c12ee1eSDan Willemsen		if diff := cmp.Diff(got, tt.want); diff != "" {
831*1c12ee1eSDan Willemsen			t.Errorf("fmt.Sprintf(%q, %s) mismatch (-got +want):\n%s", tt.fmt, tt.path, diff)
832*1c12ee1eSDan Willemsen		}
833*1c12ee1eSDan Willemsen	}
834*1c12ee1eSDan Willemsen}
835*1c12ee1eSDan Willemsen
836*1c12ee1eSDan Willemsen// compactMultiFormat returns the single line form of a multi line output.
837*1c12ee1eSDan Willemsenfunc compactMultiFormat(s string) string {
838*1c12ee1eSDan Willemsen	var b []byte
839*1c12ee1eSDan Willemsen	for _, s := range strings.Split(s, "\n") {
840*1c12ee1eSDan Willemsen		s = strings.TrimSpace(s)
841*1c12ee1eSDan Willemsen		s = regexp.MustCompile(": +").ReplaceAllString(s, ": ")
842*1c12ee1eSDan Willemsen		prevWord := len(b) > 0 && b[len(b)-1] != '[' && b[len(b)-1] != '{'
843*1c12ee1eSDan Willemsen		nextWord := len(s) > 0 && s[0] != ']' && s[0] != '}'
844*1c12ee1eSDan Willemsen		if prevWord && nextWord {
845*1c12ee1eSDan Willemsen			b = append(b, ", "...)
846*1c12ee1eSDan Willemsen		}
847*1c12ee1eSDan Willemsen		b = append(b, s...)
848*1c12ee1eSDan Willemsen	}
849*1c12ee1eSDan Willemsen	return string(b)
850*1c12ee1eSDan Willemsen}
851