1// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package impl_test
6
7import (
8	"io"
9	"reflect"
10	"sync"
11	"testing"
12
13	"github.com/google/go-cmp/cmp"
14
15	"google.golang.org/protobuf/encoding/prototext"
16	"google.golang.org/protobuf/internal/impl"
17	"google.golang.org/protobuf/reflect/protodesc"
18	"google.golang.org/protobuf/reflect/protoreflect"
19	"google.golang.org/protobuf/runtime/protoiface"
20	"google.golang.org/protobuf/testing/protocmp"
21
22	"google.golang.org/protobuf/types/descriptorpb"
23)
24
25type AberrantMessage struct {
26	OptionalBool     *bool            `protobuf:"varint,1,opt,name=opt_bool,def=1"`
27	OptionalInt32    *int32           `protobuf:"varint,2,opt,name=opt_int32,def=-12345"`
28	OptionalSint32   *int32           `protobuf:"zigzag32,3,opt,name=opt_sint32,def=-3200"`
29	OptionalUint32   *uint32          `protobuf:"varint,4,opt,name=opt_uint32,def=3200"`
30	OptionalInt64    *int64           `protobuf:"varint,5,opt,name=opt_int64,def=-123456789"`
31	OptionalSint64   *int64           `protobuf:"zigzag64,6,opt,name=opt_sint64,def=-6400"`
32	OptionalUint64   *uint64          `protobuf:"varint,7,opt,name=opt_uint64,def=6400"`
33	OptionalFixed32  *uint32          `protobuf:"fixed32,8,opt,name=opt_fixed32,def=320000"`
34	OptionalSfixed32 *int32           `protobuf:"fixed32,9,opt,name=opt_sfixed32,def=-320000"`
35	OptionalFloat    *float32         `protobuf:"fixed32,10,opt,name=opt_float,def=3.14159"`
36	OptionalFixed64  *uint64          `protobuf:"fixed64,11,opt,name=opt_fixed64,def=640000"`
37	OptionalSfixed64 *int64           `protobuf:"fixed64,12,opt,name=opt_sfixed64,def=-640000"`
38	OptionalDouble   *float64         `protobuf:"fixed64,13,opt,name=opt_double,def=3.14159265359"`
39	OptionalString   *string          `protobuf:"bytes,14,opt,name=opt_string,def=hello, \"world!\"\n"`
40	OptionalBytes    []byte           `protobuf:"bytes,15,opt,name=opt_bytes,def=dead\\336\\255\\276\\357beef"`
41	OptionalEnum     *AberrantEnum    `protobuf:"varint,16,opt,name=opt_enum,enum=google.golang.org.example.AberrantEnum,def=0"`
42	OptionalMessage  *AberrantMessage `protobuf:"bytes,17,opt,name=opt_message"`
43
44	RepeatedBool     []bool             `protobuf:"varint,18,rep,packed,name=rep_bool"`
45	RepeatedInt32    []int32            `protobuf:"varint,19,rep,packed,name=rep_int32"`
46	RepeatedSint32   []int32            `protobuf:"zigzag32,20,rep,packed,name=rep_sint32"`
47	RepeatedUint32   []uint32           `protobuf:"varint,21,rep,packed,name=rep_uint32"`
48	RepeatedInt64    []int64            `protobuf:"varint,22,rep,packed,name=rep_int64"`
49	RepeatedSint64   []int64            `protobuf:"zigzag64,23,rep,packed,name=rep_sint64"`
50	RepeatedUint64   []uint64           `protobuf:"varint,24,rep,packed,name=rep_uint64"`
51	RepeatedFixed32  []uint32           `protobuf:"fixed32,25,rep,packed,name=rep_fixed32"`
52	RepeatedSfixed32 []int32            `protobuf:"fixed32,26,rep,packed,name=rep_sfixed32"`
53	RepeatedFloat    []float32          `protobuf:"fixed32,27,rep,packed,name=rep_float"`
54	RepeatedFixed64  []uint64           `protobuf:"fixed64,28,rep,packed,name=rep_fixed64"`
55	RepeatedSfixed64 []int64            `protobuf:"fixed64,29,rep,packed,name=rep_sfixed64"`
56	RepeatedDouble   []float64          `protobuf:"fixed64,30,rep,packed,name=rep_double"`
57	RepeatedString   []string           `protobuf:"bytes,31,rep,name=rep_string"`
58	RepeatedBytes    [][]byte           `protobuf:"bytes,32,rep,name=rep_bytes"`
59	RepeatedEnum     []AberrantEnum     `protobuf:"varint,33,rep,name=rep_enum,enum=google.golang.org.example.AberrantEnum"`
60	RepeatedMessage  []*AberrantMessage `protobuf:"bytes,34,rep,name=rep_message"`
61
62	MapStringBool     map[string]bool             `protobuf:"bytes,35,rep,name=map_string_bool"     protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"`
63	MapStringInt32    map[string]int32            `protobuf:"bytes,36,rep,name=map_string_int32"    protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"`
64	MapStringSint32   map[string]int32            `protobuf:"bytes,37,rep,name=map_string_sint32"   protobuf_key:"bytes,1,opt,name=key" protobuf_val:"zigzag32,2,opt,name=value"`
65	MapStringUint32   map[string]uint32           `protobuf:"bytes,38,rep,name=map_string_uint32"   protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"`
66	MapStringInt64    map[string]int64            `protobuf:"bytes,39,rep,name=map_string_int64"    protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"`
67	MapStringSint64   map[string]int64            `protobuf:"bytes,40,rep,name=map_string_sint64"   protobuf_key:"bytes,1,opt,name=key" protobuf_val:"zigzag64,2,opt,name=value"`
68	MapStringUint64   map[string]uint64           `protobuf:"bytes,41,rep,name=map_string_uint64"   protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"`
69	MapStringFixed32  map[string]uint32           `protobuf:"bytes,42,rep,name=map_string_fixed32"  protobuf_key:"bytes,1,opt,name=key" protobuf_val:"fixed32,2,opt,name=value"`
70	MapStringSfixed32 map[string]int32            `protobuf:"bytes,43,rep,name=map_string_sfixed32" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"fixed32,2,opt,name=value"`
71	MapStringFloat    map[string]float32          `protobuf:"bytes,44,rep,name=map_string_float"    protobuf_key:"bytes,1,opt,name=key" protobuf_val:"fixed32,2,opt,name=value"`
72	MapStringFixed64  map[string]uint64           `protobuf:"bytes,45,rep,name=map_string_fixed64"  protobuf_key:"bytes,1,opt,name=key" protobuf_val:"fixed64,2,opt,name=value"`
73	MapStringSfixed64 map[string]int64            `protobuf:"bytes,46,rep,name=map_string_sfixed64" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"fixed64,2,opt,name=value"`
74	MapStringDouble   map[string]float64          `protobuf:"bytes,47,rep,name=map_string_double"   protobuf_key:"bytes,1,opt,name=key" protobuf_val:"fixed64,2,opt,name=value"`
75	MapStringString   map[string]string           `protobuf:"bytes,48,rep,name=map_string_string"   protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
76	MapStringBytes    map[string][]byte           `protobuf:"bytes,49,rep,name=map_string_bytes"    protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
77	MapStringEnum     map[string]AberrantEnum     `protobuf:"bytes,50,rep,name=map_string_enum"     protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value,enum=google.golang.org.example.AberrantEnum"`
78	MapStringMessage  map[string]*AberrantMessage `protobuf:"bytes,51,rep,name=map_string_message"  protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
79
80	OneofUnion isOneofUnion `protobuf_oneof:"oneof_union"`
81
82	Ignored io.Reader
83}
84
85func (m *AberrantMessage) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
86	return []protoiface.ExtensionRangeV1{{Start: 10, End: 100}}
87}
88
89func (m *AberrantMessage) XXX_OneofFuncs() []interface{} {
90	return []interface{}{
91		(*OneofBool)(nil),
92		(*OneofInt32)(nil),
93		(*OneofSint32)(nil),
94		(*OneofUint32)(nil),
95		(*OneofInt64)(nil),
96		(*OneofSint64)(nil),
97		(*OneofUint64)(nil),
98		(*OneofFixed32)(nil),
99		(*OneofSfixed32)(nil),
100		(*OneofFloat)(nil),
101		(*OneofFixed64)(nil),
102		(*OneofSfixed64)(nil),
103		(*OneofDouble)(nil),
104		(*OneofString)(nil),
105		(*OneofBytes)(nil),
106		(*OneofEnum)(nil),
107		(*OneofMessage)(nil),
108	}
109}
110
111type isOneofUnion interface{ isOneofUnion() }
112
113type OneofBool struct {
114	OneofBool bool `protobuf:"varint,52,opt,name=oneof_bool,oneof,def=1"`
115}
116type OneofInt32 struct {
117	OneofInt32 int32 `protobuf:"varint,53,opt,name=oneof_int32,oneof,def=-12345"`
118}
119type OneofSint32 struct {
120	OneofSint32 int32 `protobuf:"zigzag32,54,opt,name=oneof_sint32,oneof,def=-3200"`
121}
122type OneofUint32 struct {
123	OneofUint32 uint32 `protobuf:"varint,55,opt,name=oneof_uint32,oneof,def=3200"`
124}
125type OneofInt64 struct {
126	OneofInt64 int64 `protobuf:"varint,56,opt,name=oneof_int64,oneof,def=-123456789"`
127}
128type OneofSint64 struct {
129	OneofSint64 int64 `protobuf:"zigzag64,57,opt,name=oneof_sint64,oneof,def=-6400"`
130}
131type OneofUint64 struct {
132	OneofUint64 uint64 `protobuf:"varint,58,opt,name=oneof_uint64,oneof,def=6400"`
133}
134type OneofFixed32 struct {
135	OneofFixed32 uint32 `protobuf:"fixed32,59,opt,name=oneof_fixed32,oneof,def=320000"`
136}
137type OneofSfixed32 struct {
138	OneofSfixed32 int32 `protobuf:"fixed32,60,opt,name=oneof_sfixed32,oneof,def=-320000"`
139}
140type OneofFloat struct {
141	OneofFloat float32 `protobuf:"fixed32,61,opt,name=oneof_float,oneof,def=3.14159"`
142}
143type OneofFixed64 struct {
144	OneofFixed64 uint64 `protobuf:"fixed64,62,opt,name=oneof_fixed64,oneof,def=640000"`
145}
146type OneofSfixed64 struct {
147	OneofSfixed64 int64 `protobuf:"fixed64,63,opt,name=oneof_sfixed64,oneof,def=-640000"`
148}
149type OneofDouble struct {
150	OneofDouble float64 `protobuf:"fixed64,64,opt,name=oneof_double,oneof,def=3.14159265359"`
151}
152type OneofString struct {
153	OneofString string `protobuf:"bytes,65,opt,name=oneof_string,oneof,def=hello, \"world!\"\n"`
154}
155type OneofBytes struct {
156	OneofBytes []byte `protobuf:"bytes,66,opt,name=oneof_bytes,oneof,def=dead\\336\\255\\276\\357beef"`
157}
158type OneofEnum struct {
159	OneofEnum AberrantEnum `protobuf:"varint,67,opt,name=oneof_enum,enum=google.golang.org.example.AberrantEnum,oneof,def=0"`
160}
161type OneofMessage struct {
162	OneofMessage *AberrantMessage `protobuf:"bytes,68,opt,name=oneof_message,oneof"`
163}
164
165func (OneofBool) isOneofUnion()     {}
166func (OneofInt32) isOneofUnion()    {}
167func (OneofSint32) isOneofUnion()   {}
168func (OneofUint32) isOneofUnion()   {}
169func (OneofInt64) isOneofUnion()    {}
170func (OneofSint64) isOneofUnion()   {}
171func (OneofUint64) isOneofUnion()   {}
172func (OneofFixed32) isOneofUnion()  {}
173func (OneofSfixed32) isOneofUnion() {}
174func (OneofFloat) isOneofUnion()    {}
175func (OneofFixed64) isOneofUnion()  {}
176func (OneofSfixed64) isOneofUnion() {}
177func (OneofDouble) isOneofUnion()   {}
178func (OneofString) isOneofUnion()   {}
179func (OneofBytes) isOneofUnion()    {}
180func (OneofEnum) isOneofUnion()     {}
181func (OneofMessage) isOneofUnion()  {}
182
183type AberrantEnum int32
184
185func TestAberrantMessages(t *testing.T) {
186	enumName := impl.AberrantDeriveFullName(reflect.TypeOf(AberrantEnum(0)))
187	messageName := impl.AberrantDeriveFullName(reflect.TypeOf(AberrantMessage{}))
188
189	want := new(descriptorpb.DescriptorProto)
190	if err := prototext.Unmarshal([]byte(`
191		name: "AberrantMessage"
192		field: [
193			{name:"opt_bool"     number:1  label:LABEL_OPTIONAL type:TYPE_BOOL     default_value:"true"},
194			{name:"opt_int32"    number:2  label:LABEL_OPTIONAL type:TYPE_INT32    default_value:"-12345"},
195			{name:"opt_sint32"   number:3  label:LABEL_OPTIONAL type:TYPE_SINT32   default_value:"-3200"},
196			{name:"opt_uint32"   number:4  label:LABEL_OPTIONAL type:TYPE_UINT32   default_value:"3200"},
197			{name:"opt_int64"    number:5  label:LABEL_OPTIONAL type:TYPE_INT64    default_value:"-123456789"},
198			{name:"opt_sint64"   number:6  label:LABEL_OPTIONAL type:TYPE_SINT64   default_value:"-6400"},
199			{name:"opt_uint64"   number:7  label:LABEL_OPTIONAL type:TYPE_UINT64   default_value:"6400"},
200			{name:"opt_fixed32"  number:8  label:LABEL_OPTIONAL type:TYPE_FIXED32  default_value:"320000"},
201			{name:"opt_sfixed32" number:9  label:LABEL_OPTIONAL type:TYPE_SFIXED32 default_value:"-320000"},
202			{name:"opt_float"    number:10 label:LABEL_OPTIONAL type:TYPE_FLOAT    default_value:"3.14159"},
203			{name:"opt_fixed64"  number:11 label:LABEL_OPTIONAL type:TYPE_FIXED64  default_value:"640000"},
204			{name:"opt_sfixed64" number:12 label:LABEL_OPTIONAL type:TYPE_SFIXED64 default_value:"-640000"},
205			{name:"opt_double"   number:13 label:LABEL_OPTIONAL type:TYPE_DOUBLE   default_value:"3.14159265359"},
206			{name:"opt_string"   number:14 label:LABEL_OPTIONAL type:TYPE_STRING   default_value:"hello, \"world!\"\n"},
207			{name:"opt_bytes"    number:15 label:LABEL_OPTIONAL type:TYPE_BYTES    default_value:"dead\\336\\255\\276\\357beef"},
208			{name:"opt_enum"     number:16 label:LABEL_OPTIONAL type:TYPE_ENUM     type_name:".`+enumName+`" default_value:"UNKNOWN_0"},
209			{name:"opt_message"  number:17 label:LABEL_OPTIONAL type:TYPE_MESSAGE  type_name:".`+messageName+`"},
210
211			{name:"rep_bool"     number:18 label:LABEL_REPEATED type:TYPE_BOOL     options:{packed:true}},
212			{name:"rep_int32"    number:19 label:LABEL_REPEATED type:TYPE_INT32    options:{packed:true}},
213			{name:"rep_sint32"   number:20 label:LABEL_REPEATED type:TYPE_SINT32   options:{packed:true}},
214			{name:"rep_uint32"   number:21 label:LABEL_REPEATED type:TYPE_UINT32   options:{packed:true}},
215			{name:"rep_int64"    number:22 label:LABEL_REPEATED type:TYPE_INT64    options:{packed:true}},
216			{name:"rep_sint64"   number:23 label:LABEL_REPEATED type:TYPE_SINT64   options:{packed:true}},
217			{name:"rep_uint64"   number:24 label:LABEL_REPEATED type:TYPE_UINT64   options:{packed:true}},
218			{name:"rep_fixed32"  number:25 label:LABEL_REPEATED type:TYPE_FIXED32  options:{packed:true}},
219			{name:"rep_sfixed32" number:26 label:LABEL_REPEATED type:TYPE_SFIXED32 options:{packed:true}},
220			{name:"rep_float"    number:27 label:LABEL_REPEATED type:TYPE_FLOAT    options:{packed:true}},
221			{name:"rep_fixed64"  number:28 label:LABEL_REPEATED type:TYPE_FIXED64  options:{packed:true}},
222			{name:"rep_sfixed64" number:29 label:LABEL_REPEATED type:TYPE_SFIXED64 options:{packed:true}},
223			{name:"rep_double"   number:30 label:LABEL_REPEATED type:TYPE_DOUBLE   options:{packed:true}},
224			{name:"rep_string"   number:31 label:LABEL_REPEATED type:TYPE_STRING},
225			{name:"rep_bytes"    number:32 label:LABEL_REPEATED type:TYPE_BYTES},
226			{name:"rep_enum"     number:33 label:LABEL_REPEATED type:TYPE_ENUM     type_name:".`+enumName+`"},
227			{name:"rep_message"  number:34 label:LABEL_REPEATED type:TYPE_MESSAGE  type_name:".`+messageName+`"},
228
229			{name:"map_string_bool"     number:35 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringBoolEntry"},
230			{name:"map_string_int32"    number:36 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringInt32Entry"},
231			{name:"map_string_sint32"   number:37 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringSint32Entry"},
232			{name:"map_string_uint32"   number:38 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringUint32Entry"},
233			{name:"map_string_int64"    number:39 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringInt64Entry"},
234			{name:"map_string_sint64"   number:40 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringSint64Entry"},
235			{name:"map_string_uint64"   number:41 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringUint64Entry"},
236			{name:"map_string_fixed32"  number:42 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringFixed32Entry"},
237			{name:"map_string_sfixed32" number:43 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringSfixed32Entry"},
238			{name:"map_string_float"    number:44 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringFloatEntry"},
239			{name:"map_string_fixed64"  number:45 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringFixed64Entry"},
240			{name:"map_string_sfixed64" number:46 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringSfixed64Entry"},
241			{name:"map_string_double"   number:47 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringDoubleEntry"},
242			{name:"map_string_string"   number:48 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringStringEntry"},
243			{name:"map_string_bytes"    number:49 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringBytesEntry"},
244			{name:"map_string_enum"     number:50 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringEnumEntry"},
245			{name:"map_string_message"  number:51 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".`+messageName+`.MapStringMessageEntry"},
246
247			{name:"oneof_bool"     number:52 label:LABEL_OPTIONAL type:TYPE_BOOL     oneof_index:0 default_value:"true"},
248			{name:"oneof_int32"    number:53 label:LABEL_OPTIONAL type:TYPE_INT32    oneof_index:0 default_value:"-12345"},
249			{name:"oneof_sint32"   number:54 label:LABEL_OPTIONAL type:TYPE_SINT32   oneof_index:0 default_value:"-3200"},
250			{name:"oneof_uint32"   number:55 label:LABEL_OPTIONAL type:TYPE_UINT32   oneof_index:0 default_value:"3200"},
251			{name:"oneof_int64"    number:56 label:LABEL_OPTIONAL type:TYPE_INT64    oneof_index:0 default_value:"-123456789"},
252			{name:"oneof_sint64"   number:57 label:LABEL_OPTIONAL type:TYPE_SINT64   oneof_index:0 default_value:"-6400"},
253			{name:"oneof_uint64"   number:58 label:LABEL_OPTIONAL type:TYPE_UINT64   oneof_index:0 default_value:"6400"},
254			{name:"oneof_fixed32"  number:59 label:LABEL_OPTIONAL type:TYPE_FIXED32  oneof_index:0 default_value:"320000"},
255			{name:"oneof_sfixed32" number:60 label:LABEL_OPTIONAL type:TYPE_SFIXED32 oneof_index:0 default_value:"-320000"},
256			{name:"oneof_float"    number:61 label:LABEL_OPTIONAL type:TYPE_FLOAT    oneof_index:0 default_value:"3.14159"},
257			{name:"oneof_fixed64"  number:62 label:LABEL_OPTIONAL type:TYPE_FIXED64  oneof_index:0 default_value:"640000"},
258			{name:"oneof_sfixed64" number:63 label:LABEL_OPTIONAL type:TYPE_SFIXED64 oneof_index:0 default_value:"-640000"},
259			{name:"oneof_double"   number:64 label:LABEL_OPTIONAL type:TYPE_DOUBLE   oneof_index:0 default_value:"3.14159265359"},
260			{name:"oneof_string"   number:65 label:LABEL_OPTIONAL type:TYPE_STRING   oneof_index:0 default_value:"hello, \"world!\"\n"},
261			{name:"oneof_bytes"    number:66 label:LABEL_OPTIONAL type:TYPE_BYTES    oneof_index:0 default_value:"dead\\336\\255\\276\\357beef"},
262			{name:"oneof_enum"     number:67 label:LABEL_OPTIONAL type:TYPE_ENUM     oneof_index:0 type_name:".`+enumName+`" default_value:"UNKNOWN_0"},
263			{name:"oneof_message"  number:68 label:LABEL_OPTIONAL type:TYPE_MESSAGE  oneof_index:0 type_name:".`+messageName+`"}
264		]
265		oneof_decl: [{name:"oneof_union"}]
266		extension_range: [{start:10 end:101}]
267		nested_type: [
268			{name:"MapStringBoolEntry"     field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_BOOL}]     options:{map_entry:true}},
269			{name:"MapStringInt32Entry"    field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_INT32}]    options:{map_entry:true}},
270			{name:"MapStringSint32Entry"   field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_SINT32}]   options:{map_entry:true}},
271			{name:"MapStringUint32Entry"   field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_UINT32}]   options:{map_entry:true}},
272			{name:"MapStringInt64Entry"    field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_INT64}]    options:{map_entry:true}},
273			{name:"MapStringSint64Entry"   field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_SINT64}]   options:{map_entry:true}},
274			{name:"MapStringUint64Entry"   field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_UINT64}]   options:{map_entry:true}},
275			{name:"MapStringFixed32Entry"  field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_FIXED32}]  options:{map_entry:true}},
276			{name:"MapStringSfixed32Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_SFIXED32}] options:{map_entry:true}},
277			{name:"MapStringFloatEntry"    field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_FLOAT}]    options:{map_entry:true}},
278			{name:"MapStringFixed64Entry"  field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_FIXED64}]  options:{map_entry:true}},
279			{name:"MapStringSfixed64Entry" field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_SFIXED64}] options:{map_entry:true}},
280			{name:"MapStringDoubleEntry"   field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_DOUBLE}]   options:{map_entry:true}},
281			{name:"MapStringStringEntry"   field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}]   options:{map_entry:true}},
282			{name:"MapStringBytesEntry"    field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_BYTES}]    options:{map_entry:true}},
283			{name:"MapStringEnumEntry"     field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_ENUM    type_name:".`+enumName+`"}] options:{map_entry:true}},
284			{name:"MapStringMessageEntry"  field:[{name:"key" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, {name:"value" number:2 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".`+messageName+`"}]                  options:{map_entry:true}}
285		]
286	`), want); err != nil {
287		t.Fatalf("prototext.Unmarshal() error: %v", err)
288	}
289
290	md := impl.LegacyLoadMessageDesc(reflect.TypeOf(&AberrantMessage{}))
291	got := protodesc.ToDescriptorProto(md)
292	if diff := cmp.Diff(want, got, protocmp.Transform()); diff != "" {
293		t.Errorf("mismatching descriptor (-want +got):\n%s", diff)
294	}
295}
296
297type AberrantMessage1 struct {
298	M *AberrantMessage2 `protobuf:"bytes,1,opt,name=message"`
299}
300
301type AberrantMessage2 struct {
302	M *AberrantMessage1 `protobuf:"bytes,1,opt,name=message"`
303}
304
305func TestAberrantRace(t *testing.T) {
306	var gotMD1, wantMD1, gotMD2, wantMD2 protoreflect.MessageDescriptor
307
308	var wg sync.WaitGroup
309	wg.Add(2)
310	go func() {
311		defer wg.Done()
312		md := impl.LegacyLoadMessageDesc(reflect.TypeOf(&AberrantMessage1{}))
313		wantMD2 = md.Fields().Get(0).Message()
314		gotMD2 = wantMD2.Fields().Get(0).Message().Fields().Get(0).Message()
315	}()
316	go func() {
317		defer wg.Done()
318		md := impl.LegacyLoadMessageDesc(reflect.TypeOf(&AberrantMessage2{}))
319		wantMD1 = md.Fields().Get(0).Message()
320		gotMD1 = wantMD1.Fields().Get(0).Message().Fields().Get(0).Message()
321	}()
322	wg.Wait()
323
324	if gotMD1 != wantMD1 || gotMD2 != wantMD2 {
325		t.Errorf("mismatching exact message descriptors")
326	}
327}
328
329func TestAberrantExtensions(t *testing.T) {
330	tests := []struct {
331		in              *impl.ExtensionInfo
332		wantName        protoreflect.FullName
333		wantNumber      protoreflect.FieldNumber
334		wantPlaceholder bool
335	}{{
336		in:              &impl.ExtensionInfo{Field: 500},
337		wantNumber:      500,
338		wantPlaceholder: true,
339	}, {
340		in:              &impl.ExtensionInfo{Name: "foo.bar.baz"},
341		wantName:        "foo.bar.baz",
342		wantPlaceholder: true,
343	}}
344
345	for _, tt := range tests {
346		t.Run("", func(t *testing.T) {
347			xtd := tt.in.TypeDescriptor()
348			switch {
349			case xtd.FullName() != tt.wantName:
350				t.Errorf("FullName() = %v, want %v", xtd.FullName(), tt.wantName)
351			case xtd.Number() != tt.wantNumber:
352				t.Errorf("Number() = %v, want %v", xtd.Number(), tt.wantNumber)
353			case xtd.IsPlaceholder() != tt.wantPlaceholder:
354				t.Errorf("IsPlaceholder() = %v, want %v", xtd.IsPlaceholder(), tt.wantPlaceholder)
355			}
356		})
357	}
358}
359