blob: d6ca9418b6694a8beeed1c53862ba3374f4345b2 [file] [log] [blame]
Joe Tsai90fe9962018-10-18 11:06:29 -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 Tsai08e00302018-11-26 22:32:06 -08005package impl_test
Joe Tsai90fe9962018-10-18 11:06:29 -07006
7import (
Joe Tsaie2afdc22018-10-25 14:06:56 -07008 "bytes"
9 "math"
Joe Tsai90fe9962018-10-18 11:06:29 -070010 "reflect"
Joe Tsai21ade492019-05-22 13:42:54 -040011 "sync"
Joe Tsai90fe9962018-10-18 11:06:29 -070012 "testing"
13
Joe Tsaiea118132018-11-11 17:56:21 -080014 cmp "github.com/google/go-cmp/cmp"
Joe Tsai08e00302018-11-26 22:32:06 -080015 cmpopts "github.com/google/go-cmp/cmp/cmpopts"
Damien Neile89e6242019-05-13 23:55:40 -070016 pack "google.golang.org/protobuf/internal/encoding/pack"
17 pimpl "google.golang.org/protobuf/internal/impl"
Damien Neile89e6242019-05-13 23:55:40 -070018 pragma "google.golang.org/protobuf/internal/pragma"
19 ptype "google.golang.org/protobuf/internal/prototype"
20 scalar "google.golang.org/protobuf/internal/scalar"
21 pref "google.golang.org/protobuf/reflect/protoreflect"
22 preg "google.golang.org/protobuf/reflect/protoregistry"
23 piface "google.golang.org/protobuf/runtime/protoiface"
Joe Tsaiea118132018-11-11 17:56:21 -080024
Damien Neile89e6242019-05-13 23:55:40 -070025 proto2_20180125 "google.golang.org/protobuf/internal/testprotos/legacy/proto2.v1.0.0-20180125-92554152"
Joe Tsai90fe9962018-10-18 11:06:29 -070026)
27
Joe Tsaif0c01e42018-11-06 13:05:20 -080028type legacyTestMessage struct {
Joe Tsai4fddeba2019-03-20 18:29:32 -070029 XXX_unrecognized []byte
Joe Tsai00e50dc2019-04-16 12:39:41 -070030 XXX_InternalExtensions map[int32]pimpl.ExtensionFieldV1
Joe Tsai95b02902018-10-31 18:23:42 -070031}
32
Joe Tsaif0c01e42018-11-06 13:05:20 -080033func (*legacyTestMessage) Reset() {}
34func (*legacyTestMessage) String() string { return "" }
35func (*legacyTestMessage) ProtoMessage() {}
Joe Tsai4fddeba2019-03-20 18:29:32 -070036func (*legacyTestMessage) ExtensionRangeArray() []piface.ExtensionRangeV1 {
37 return []piface.ExtensionRangeV1{{Start: 10, End: 20}, {Start: 40, End: 80}, {Start: 10000, End: 20000}}
Joe Tsai95b02902018-10-31 18:23:42 -070038}
39
Joe Tsai0fc49f82019-05-01 12:29:25 -070040func init() {
41 mt := pimpl.Export{}.MessageTypeOf(&legacyTestMessage{})
42 preg.GlobalTypes.Register(mt)
43}
44
Joe Tsaie2afdc22018-10-25 14:06:56 -070045func TestLegacyUnknown(t *testing.T) {
46 rawOf := func(toks ...pack.Token) pref.RawFields {
47 return pref.RawFields(pack.Message(toks).Marshal())
48 }
Joe Tsai00a323d2019-05-06 23:27:29 -070049 raw1 := rawOf(pack.Tag{1, pack.BytesType}, pack.Bytes("1")) // 0a0131
Joe Tsaie2afdc22018-10-25 14:06:56 -070050 raw1a := rawOf(pack.Tag{1, pack.VarintType}, pack.Svarint(-4321)) // 08c143
51 raw1b := rawOf(pack.Tag{1, pack.Fixed32Type}, pack.Uint32(0xdeadbeef)) // 0defbeadde
52 raw1c := rawOf(pack.Tag{1, pack.Fixed64Type}, pack.Float64(math.Pi)) // 09182d4454fb210940
53 raw2a := rawOf(pack.Tag{2, pack.BytesType}, pack.String("hello, world!")) // 120d68656c6c6f2c20776f726c6421
54 raw2b := rawOf(pack.Tag{2, pack.VarintType}, pack.Uvarint(1234)) // 10d209
55 raw3a := rawOf(pack.Tag{3, pack.StartGroupType}, pack.Tag{3, pack.EndGroupType}) // 1b1c
56 raw3b := rawOf(pack.Tag{3, pack.BytesType}, pack.Bytes("\xde\xad\xbe\xef")) // 1a04deadbeef
57
58 joinRaw := func(bs ...pref.RawFields) (out []byte) {
59 for _, b := range bs {
60 out = append(out, b...)
61 }
62 return out
63 }
64
Joe Tsaif0c01e42018-11-06 13:05:20 -080065 m := new(legacyTestMessage)
Joe Tsai08e00302018-11-26 22:32:06 -080066 fs := pimpl.Export{}.MessageOf(m).UnknownFields()
Joe Tsai95b02902018-10-31 18:23:42 -070067
Joe Tsaie2afdc22018-10-25 14:06:56 -070068 if got, want := fs.Len(), 0; got != want {
69 t.Errorf("Len() = %d, want %d", got, want)
70 }
Joe Tsai95b02902018-10-31 18:23:42 -070071 if got, want := m.XXX_unrecognized, joinRaw(); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -070072 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
73 }
74
75 fs.Set(1, raw1a)
76 fs.Set(1, append(fs.Get(1), raw1b...))
77 fs.Set(1, append(fs.Get(1), raw1c...))
78 if got, want := fs.Len(), 1; got != want {
79 t.Errorf("Len() = %d, want %d", got, want)
80 }
Joe Tsai95b02902018-10-31 18:23:42 -070081 if got, want := m.XXX_unrecognized, joinRaw(raw1a, raw1b, raw1c); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -070082 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
83 }
84
85 fs.Set(2, raw2a)
86 if got, want := fs.Len(), 2; got != want {
87 t.Errorf("Len() = %d, want %d", got, want)
88 }
Joe Tsai95b02902018-10-31 18:23:42 -070089 if got, want := m.XXX_unrecognized, joinRaw(raw1a, raw1b, raw1c, raw2a); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -070090 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
91 }
92
93 if got, want := fs.Get(1), joinRaw(raw1a, raw1b, raw1c); !bytes.Equal(got, want) {
94 t.Errorf("Get(%d) = %x, want %x", 1, got, want)
95 }
96 if got, want := fs.Get(2), joinRaw(raw2a); !bytes.Equal(got, want) {
97 t.Errorf("Get(%d) = %x, want %x", 2, got, want)
98 }
99 if got, want := fs.Get(3), joinRaw(); !bytes.Equal(got, want) {
100 t.Errorf("Get(%d) = %x, want %x", 3, got, want)
101 }
102
103 fs.Set(1, nil) // remove field 1
104 if got, want := fs.Len(), 1; got != want {
105 t.Errorf("Len() = %d, want %d", got, want)
106 }
Joe Tsai95b02902018-10-31 18:23:42 -0700107 if got, want := m.XXX_unrecognized, joinRaw(raw2a); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -0700108 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
109 }
110
111 // Simulate manual appending of raw field data.
Joe Tsai95b02902018-10-31 18:23:42 -0700112 m.XXX_unrecognized = append(m.XXX_unrecognized, joinRaw(raw3a, raw1a, raw1b, raw2b, raw3b, raw1c)...)
Joe Tsaie2afdc22018-10-25 14:06:56 -0700113 if got, want := fs.Len(), 3; got != want {
114 t.Errorf("Len() = %d, want %d", got, want)
115 }
116
117 // Verify range iteration order.
118 var i int
119 want := []struct {
120 num pref.FieldNumber
121 raw pref.RawFields
122 }{
Joe Tsaie2afdc22018-10-25 14:06:56 -0700123 {2, joinRaw(raw2a, raw2b)},
Joe Tsai2d5a1692018-10-29 02:10:42 -0700124 {3, joinRaw(raw3a, raw3b)},
Joe Tsaie2afdc22018-10-25 14:06:56 -0700125 {1, joinRaw(raw1a, raw1b, raw1c)},
126 }
127 fs.Range(func(num pref.FieldNumber, raw pref.RawFields) bool {
128 if i < len(want) {
129 if num != want[i].num || !bytes.Equal(raw, want[i].raw) {
130 t.Errorf("Range(%d) = (%d, %x), want (%d, %x)", i, num, raw, want[i].num, want[i].raw)
131 }
132 } else {
133 t.Errorf("unexpected Range iteration: %d", i)
134 }
135 i++
136 return true
137 })
138
139 fs.Set(2, fs.Get(2)) // moves field 2 to the end
140 if got, want := fs.Len(), 3; got != want {
141 t.Errorf("Len() = %d, want %d", got, want)
142 }
Joe Tsai95b02902018-10-31 18:23:42 -0700143 if got, want := m.XXX_unrecognized, joinRaw(raw3a, raw1a, raw1b, raw3b, raw1c, raw2a, raw2b); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -0700144 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
145 }
146 fs.Set(1, nil) // remove field 1
147 if got, want := fs.Len(), 2; got != want {
148 t.Errorf("Len() = %d, want %d", got, want)
149 }
Joe Tsai95b02902018-10-31 18:23:42 -0700150 if got, want := m.XXX_unrecognized, joinRaw(raw3a, raw3b, raw2a, raw2b); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -0700151 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
152 }
153
154 // Remove all fields.
155 fs.Range(func(n pref.FieldNumber, b pref.RawFields) bool {
156 fs.Set(n, nil)
157 return true
158 })
159 if got, want := fs.Len(), 0; got != want {
160 t.Errorf("Len() = %d, want %d", got, want)
161 }
Joe Tsai95b02902018-10-31 18:23:42 -0700162 if got, want := m.XXX_unrecognized, joinRaw(); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -0700163 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
164 }
Joe Tsai95b02902018-10-31 18:23:42 -0700165
166 fs.Set(1, raw1)
167 if got, want := fs.Len(), 1; got != want {
168 t.Errorf("Len() = %d, want %d", got, want)
169 }
170 if got, want := m.XXX_unrecognized, joinRaw(raw1); !bytes.Equal(got, want) {
171 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
172 }
Joe Tsaie2afdc22018-10-25 14:06:56 -0700173}
Joe Tsaif0c01e42018-11-06 13:05:20 -0800174
Joe Tsai08e00302018-11-26 22:32:06 -0800175var (
Joe Tsai21ade492019-05-22 13:42:54 -0400176 testParentDesc = pimpl.Export{}.MessageDescriptorOf((*legacyTestMessage)(nil))
177 testEnumV1Desc = pimpl.Export{}.EnumDescriptorOf(proto2_20180125.Message_ChildEnum(0))
178 testMessageV1Desc = pimpl.Export{}.MessageDescriptorOf((*proto2_20180125.Message_ChildMessage)(nil))
179 testEnumV2Desc = enumProto2Type.Descriptor()
180 testMessageV2Desc = enumMessagesType.PBType.Descriptor()
Joe Tsai08e00302018-11-26 22:32:06 -0800181
182 extensionTypes = []pref.ExtensionType{
183 mustMakeExtensionType(&ptype.StandaloneExtension{
184 FullName: "fizz.buzz.optional_bool",
185 Number: 10000,
186 Cardinality: pref.Optional,
187 Kind: pref.BoolKind,
188 Default: pref.ValueOf(true),
Joe Tsai21ade492019-05-22 13:42:54 -0400189 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800190 }, nil),
191 mustMakeExtensionType(&ptype.StandaloneExtension{
192 FullName: "fizz.buzz.optional_int32",
193 Number: 10001,
194 Cardinality: pref.Optional,
195 Kind: pref.Int32Kind,
196 Default: pref.ValueOf(int32(-12345)),
Joe Tsai21ade492019-05-22 13:42:54 -0400197 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800198 }, nil),
199 mustMakeExtensionType(&ptype.StandaloneExtension{
200 FullName: "fizz.buzz.optional_uint32",
201 Number: 10002,
202 Cardinality: pref.Optional,
203 Kind: pref.Uint32Kind,
204 Default: pref.ValueOf(uint32(3200)),
Joe Tsai21ade492019-05-22 13:42:54 -0400205 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800206 }, nil),
207 mustMakeExtensionType(&ptype.StandaloneExtension{
208 FullName: "fizz.buzz.optional_float",
209 Number: 10003,
210 Cardinality: pref.Optional,
211 Kind: pref.FloatKind,
212 Default: pref.ValueOf(float32(3.14159)),
Joe Tsai21ade492019-05-22 13:42:54 -0400213 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800214 }, nil),
215 mustMakeExtensionType(&ptype.StandaloneExtension{
216 FullName: "fizz.buzz.optional_string",
217 Number: 10004,
218 Cardinality: pref.Optional,
219 Kind: pref.StringKind,
220 Default: pref.ValueOf(string("hello, \"world!\"\n")),
Joe Tsai21ade492019-05-22 13:42:54 -0400221 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800222 }, nil),
223 mustMakeExtensionType(&ptype.StandaloneExtension{
224 FullName: "fizz.buzz.optional_bytes",
225 Number: 10005,
226 Cardinality: pref.Optional,
227 Kind: pref.BytesKind,
228 Default: pref.ValueOf([]byte("dead\xde\xad\xbe\xefbeef")),
Joe Tsai21ade492019-05-22 13:42:54 -0400229 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800230 }, nil),
231 mustMakeExtensionType(&ptype.StandaloneExtension{
232 FullName: "fizz.buzz.optional_enum_v1",
233 Number: 10006,
234 Cardinality: pref.Optional,
235 Kind: pref.EnumKind,
236 Default: pref.ValueOf(pref.EnumNumber(0)),
Joe Tsai21ade492019-05-22 13:42:54 -0400237 EnumType: testEnumV1Desc,
238 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800239 }, proto2_20180125.Message_ChildEnum(0)),
240 mustMakeExtensionType(&ptype.StandaloneExtension{
241 FullName: "fizz.buzz.optional_message_v1",
242 Number: 10007,
243 Cardinality: pref.Optional,
244 Kind: pref.MessageKind,
Joe Tsai21ade492019-05-22 13:42:54 -0400245 MessageType: testMessageV1Desc,
246 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800247 }, (*proto2_20180125.Message_ChildMessage)(nil)),
248 mustMakeExtensionType(&ptype.StandaloneExtension{
249 FullName: "fizz.buzz.optional_enum_v2",
250 Number: 10008,
251 Cardinality: pref.Optional,
252 Kind: pref.EnumKind,
253 Default: pref.ValueOf(pref.EnumNumber(57005)),
Joe Tsai21ade492019-05-22 13:42:54 -0400254 EnumType: testEnumV2Desc,
255 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800256 }, EnumProto2(0)),
257 mustMakeExtensionType(&ptype.StandaloneExtension{
258 FullName: "fizz.buzz.optional_message_v2",
259 Number: 10009,
260 Cardinality: pref.Optional,
261 Kind: pref.MessageKind,
Joe Tsai21ade492019-05-22 13:42:54 -0400262 MessageType: testMessageV2Desc,
263 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800264 }, (*EnumMessages)(nil)),
265 mustMakeExtensionType(&ptype.StandaloneExtension{
266 FullName: "fizz.buzz.repeated_bool",
267 Number: 10010,
268 Cardinality: pref.Repeated,
269 Kind: pref.BoolKind,
Joe Tsai21ade492019-05-22 13:42:54 -0400270 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800271 }, nil),
272 mustMakeExtensionType(&ptype.StandaloneExtension{
273 FullName: "fizz.buzz.repeated_int32",
274 Number: 10011,
275 Cardinality: pref.Repeated,
276 Kind: pref.Int32Kind,
Joe Tsai21ade492019-05-22 13:42:54 -0400277 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800278 }, nil),
279 mustMakeExtensionType(&ptype.StandaloneExtension{
280 FullName: "fizz.buzz.repeated_uint32",
281 Number: 10012,
282 Cardinality: pref.Repeated,
283 Kind: pref.Uint32Kind,
Joe Tsai21ade492019-05-22 13:42:54 -0400284 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800285 }, nil),
286 mustMakeExtensionType(&ptype.StandaloneExtension{
287 FullName: "fizz.buzz.repeated_float",
288 Number: 10013,
289 Cardinality: pref.Repeated,
290 Kind: pref.FloatKind,
Joe Tsai21ade492019-05-22 13:42:54 -0400291 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800292 }, nil),
293 mustMakeExtensionType(&ptype.StandaloneExtension{
294 FullName: "fizz.buzz.repeated_string",
295 Number: 10014,
296 Cardinality: pref.Repeated,
297 Kind: pref.StringKind,
Joe Tsai21ade492019-05-22 13:42:54 -0400298 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800299 }, nil),
300 mustMakeExtensionType(&ptype.StandaloneExtension{
301 FullName: "fizz.buzz.repeated_bytes",
302 Number: 10015,
303 Cardinality: pref.Repeated,
304 Kind: pref.BytesKind,
Joe Tsai21ade492019-05-22 13:42:54 -0400305 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800306 }, nil),
307 mustMakeExtensionType(&ptype.StandaloneExtension{
308 FullName: "fizz.buzz.repeated_enum_v1",
309 Number: 10016,
310 Cardinality: pref.Repeated,
311 Kind: pref.EnumKind,
Joe Tsai21ade492019-05-22 13:42:54 -0400312 EnumType: testEnumV1Desc,
313 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800314 }, proto2_20180125.Message_ChildEnum(0)),
315 mustMakeExtensionType(&ptype.StandaloneExtension{
316 FullName: "fizz.buzz.repeated_message_v1",
317 Number: 10017,
318 Cardinality: pref.Repeated,
319 Kind: pref.MessageKind,
Joe Tsai21ade492019-05-22 13:42:54 -0400320 MessageType: testMessageV1Desc,
321 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800322 }, (*proto2_20180125.Message_ChildMessage)(nil)),
323 mustMakeExtensionType(&ptype.StandaloneExtension{
324 FullName: "fizz.buzz.repeated_enum_v2",
325 Number: 10018,
326 Cardinality: pref.Repeated,
327 Kind: pref.EnumKind,
Joe Tsai21ade492019-05-22 13:42:54 -0400328 EnumType: testEnumV2Desc,
329 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800330 }, EnumProto2(0)),
331 mustMakeExtensionType(&ptype.StandaloneExtension{
332 FullName: "fizz.buzz.repeated_message_v2",
333 Number: 10019,
334 Cardinality: pref.Repeated,
335 Kind: pref.MessageKind,
Joe Tsai21ade492019-05-22 13:42:54 -0400336 MessageType: testMessageV2Desc,
337 ExtendedType: testParentDesc,
Joe Tsai08e00302018-11-26 22:32:06 -0800338 }, (*EnumMessages)(nil)),
339 }
340
Joe Tsai4fddeba2019-03-20 18:29:32 -0700341 extensionDescs = []*piface.ExtensionDescV1{{
Joe Tsai08e00302018-11-26 22:32:06 -0800342 ExtendedType: (*legacyTestMessage)(nil),
343 ExtensionType: (*bool)(nil),
344 Field: 10000,
345 Name: "fizz.buzz.optional_bool",
346 Tag: "varint,10000,opt,name=optional_bool,def=1",
347 }, {
348 ExtendedType: (*legacyTestMessage)(nil),
349 ExtensionType: (*int32)(nil),
350 Field: 10001,
351 Name: "fizz.buzz.optional_int32",
352 Tag: "varint,10001,opt,name=optional_int32,def=-12345",
353 }, {
354 ExtendedType: (*legacyTestMessage)(nil),
355 ExtensionType: (*uint32)(nil),
356 Field: 10002,
357 Name: "fizz.buzz.optional_uint32",
358 Tag: "varint,10002,opt,name=optional_uint32,def=3200",
359 }, {
360 ExtendedType: (*legacyTestMessage)(nil),
361 ExtensionType: (*float32)(nil),
362 Field: 10003,
363 Name: "fizz.buzz.optional_float",
364 Tag: "fixed32,10003,opt,name=optional_float,def=3.14159",
365 }, {
366 ExtendedType: (*legacyTestMessage)(nil),
367 ExtensionType: (*string)(nil),
368 Field: 10004,
369 Name: "fizz.buzz.optional_string",
370 Tag: "bytes,10004,opt,name=optional_string,def=hello, \"world!\"\n",
371 }, {
372 ExtendedType: (*legacyTestMessage)(nil),
373 ExtensionType: ([]byte)(nil),
374 Field: 10005,
375 Name: "fizz.buzz.optional_bytes",
376 Tag: "bytes,10005,opt,name=optional_bytes,def=dead\\336\\255\\276\\357beef",
377 }, {
378 ExtendedType: (*legacyTestMessage)(nil),
379 ExtensionType: (*proto2_20180125.Message_ChildEnum)(nil),
380 Field: 10006,
381 Name: "fizz.buzz.optional_enum_v1",
382 Tag: "varint,10006,opt,name=optional_enum_v1,enum=google.golang.org.proto2_20180125.Message_ChildEnum,def=0",
383 }, {
384 ExtendedType: (*legacyTestMessage)(nil),
385 ExtensionType: (*proto2_20180125.Message_ChildMessage)(nil),
386 Field: 10007,
387 Name: "fizz.buzz.optional_message_v1",
388 Tag: "bytes,10007,opt,name=optional_message_v1",
389 }, {
390 ExtendedType: (*legacyTestMessage)(nil),
391 ExtensionType: (*EnumProto2)(nil),
392 Field: 10008,
393 Name: "fizz.buzz.optional_enum_v2",
394 Tag: "varint,10008,opt,name=optional_enum_v2,enum=EnumProto2,def=57005",
395 }, {
396 ExtendedType: (*legacyTestMessage)(nil),
397 ExtensionType: (*EnumMessages)(nil),
398 Field: 10009,
399 Name: "fizz.buzz.optional_message_v2",
400 Tag: "bytes,10009,opt,name=optional_message_v2",
401 }, {
402 ExtendedType: (*legacyTestMessage)(nil),
403 ExtensionType: ([]bool)(nil),
404 Field: 10010,
405 Name: "fizz.buzz.repeated_bool",
406 Tag: "varint,10010,rep,name=repeated_bool",
407 }, {
408 ExtendedType: (*legacyTestMessage)(nil),
409 ExtensionType: ([]int32)(nil),
410 Field: 10011,
411 Name: "fizz.buzz.repeated_int32",
412 Tag: "varint,10011,rep,name=repeated_int32",
413 }, {
414 ExtendedType: (*legacyTestMessage)(nil),
415 ExtensionType: ([]uint32)(nil),
416 Field: 10012,
417 Name: "fizz.buzz.repeated_uint32",
418 Tag: "varint,10012,rep,name=repeated_uint32",
419 }, {
420 ExtendedType: (*legacyTestMessage)(nil),
421 ExtensionType: ([]float32)(nil),
422 Field: 10013,
423 Name: "fizz.buzz.repeated_float",
424 Tag: "fixed32,10013,rep,name=repeated_float",
425 }, {
426 ExtendedType: (*legacyTestMessage)(nil),
427 ExtensionType: ([]string)(nil),
428 Field: 10014,
429 Name: "fizz.buzz.repeated_string",
430 Tag: "bytes,10014,rep,name=repeated_string",
431 }, {
432 ExtendedType: (*legacyTestMessage)(nil),
433 ExtensionType: ([][]byte)(nil),
434 Field: 10015,
435 Name: "fizz.buzz.repeated_bytes",
436 Tag: "bytes,10015,rep,name=repeated_bytes",
437 }, {
438 ExtendedType: (*legacyTestMessage)(nil),
439 ExtensionType: ([]proto2_20180125.Message_ChildEnum)(nil),
440 Field: 10016,
441 Name: "fizz.buzz.repeated_enum_v1",
442 Tag: "varint,10016,rep,name=repeated_enum_v1,enum=google.golang.org.proto2_20180125.Message_ChildEnum",
443 }, {
444 ExtendedType: (*legacyTestMessage)(nil),
445 ExtensionType: ([]*proto2_20180125.Message_ChildMessage)(nil),
446 Field: 10017,
447 Name: "fizz.buzz.repeated_message_v1",
448 Tag: "bytes,10017,rep,name=repeated_message_v1",
449 }, {
450 ExtendedType: (*legacyTestMessage)(nil),
451 ExtensionType: ([]EnumProto2)(nil),
452 Field: 10018,
453 Name: "fizz.buzz.repeated_enum_v2",
454 Tag: "varint,10018,rep,name=repeated_enum_v2,enum=EnumProto2",
455 }, {
456 ExtendedType: (*legacyTestMessage)(nil),
457 ExtensionType: ([]*EnumMessages)(nil),
458 Field: 10019,
459 Name: "fizz.buzz.repeated_message_v2",
460 Tag: "bytes,10019,rep,name=repeated_message_v2",
461 }}
462)
463
464func TestLegacyExtensions(t *testing.T) {
Joe Tsaif0c01e42018-11-06 13:05:20 -0800465 opts := cmp.Options{cmp.Comparer(func(x, y *proto2_20180125.Message_ChildMessage) bool {
466 return x == y // pointer compare messages for object identity
467 })}
468
469 m := new(legacyTestMessage)
Joe Tsai08e00302018-11-26 22:32:06 -0800470 fs := pimpl.Export{}.MessageOf(m).KnownFields()
Joe Tsaif0c01e42018-11-06 13:05:20 -0800471 ts := fs.ExtensionTypes()
472
473 if n := fs.Len(); n != 0 {
474 t.Errorf("KnownFields.Len() = %v, want 0", n)
475 }
476 if n := ts.Len(); n != 0 {
477 t.Errorf("ExtensionFieldTypes.Len() = %v, want 0", n)
478 }
479
480 // Register all the extension types.
Joe Tsai08e00302018-11-26 22:32:06 -0800481 for _, xt := range extensionTypes {
Joe Tsaif0c01e42018-11-06 13:05:20 -0800482 ts.Register(xt)
483 }
484
485 // Check that getting the zero value returns the default value for scalars,
Joe Tsai4b7aff62018-11-14 14:05:19 -0800486 // nil for singular messages, and an empty list for repeated fields.
Joe Tsaif0c01e42018-11-06 13:05:20 -0800487 defaultValues := []interface{}{
488 bool(true),
489 int32(-12345),
490 uint32(3200),
491 float32(3.14159),
492 string("hello, \"world!\"\n"),
493 []byte("dead\xde\xad\xbe\xefbeef"),
494 proto2_20180125.Message_ALPHA,
495 nil,
Joe Tsai87b955b2018-11-14 21:59:49 -0800496 EnumProto2(0xdead),
497 nil,
Joe Tsaif0c01e42018-11-06 13:05:20 -0800498 new([]bool),
499 new([]int32),
500 new([]uint32),
501 new([]float32),
502 new([]string),
503 new([][]byte),
504 new([]proto2_20180125.Message_ChildEnum),
505 new([]*proto2_20180125.Message_ChildMessage),
Joe Tsai87b955b2018-11-14 21:59:49 -0800506 new([]EnumProto2),
507 new([]*EnumMessages),
Joe Tsaif0c01e42018-11-06 13:05:20 -0800508 }
Joe Tsai08e00302018-11-26 22:32:06 -0800509 for i, xt := range extensionTypes {
Joe Tsaif0c01e42018-11-06 13:05:20 -0800510 var got interface{}
Joe Tsai0fc49f82019-05-01 12:29:25 -0700511 num := xt.Descriptor().Number()
512 if v := fs.Get(num); v.IsValid() {
Joe Tsaif6d4a422018-11-19 14:26:06 -0800513 got = xt.InterfaceOf(v)
Joe Tsaif0c01e42018-11-06 13:05:20 -0800514 }
515 want := defaultValues[i]
516 if diff := cmp.Diff(want, got, opts); diff != "" {
Joe Tsai0fc49f82019-05-01 12:29:25 -0700517 t.Errorf("KnownFields.Get(%d) mismatch (-want +got):\n%v", num, diff)
Joe Tsaif0c01e42018-11-06 13:05:20 -0800518 }
519 }
520
521 // All fields should be unpopulated.
Joe Tsai08e00302018-11-26 22:32:06 -0800522 for _, xt := range extensionTypes {
Joe Tsai0fc49f82019-05-01 12:29:25 -0700523 num := xt.Descriptor().Number()
524 if fs.Has(num) {
525 t.Errorf("KnownFields.Has(%d) = true, want false", num)
Joe Tsaif0c01e42018-11-06 13:05:20 -0800526 }
527 }
528
Joe Tsai4b7aff62018-11-14 14:05:19 -0800529 // Set some values and append to values to the lists.
Joe Tsai009e0672018-11-27 18:45:07 -0800530 m1a := &proto2_20180125.Message_ChildMessage{F1: scalar.String("m1a")}
531 m1b := &proto2_20180125.Message_ChildMessage{F1: scalar.String("m2b")}
Joe Tsai87b955b2018-11-14 21:59:49 -0800532 m2a := &EnumMessages{EnumP2: EnumProto2(0x1b).Enum()}
533 m2b := &EnumMessages{EnumP2: EnumProto2(0x2b).Enum()}
Joe Tsaif0c01e42018-11-06 13:05:20 -0800534 setValues := []interface{}{
535 bool(false),
536 int32(-54321),
537 uint32(6400),
538 float32(2.71828),
539 string("goodbye, \"world!\"\n"),
540 []byte("live\xde\xad\xbe\xefchicken"),
541 proto2_20180125.Message_CHARLIE,
Joe Tsai87b955b2018-11-14 21:59:49 -0800542 m1a,
543 EnumProto2(0xbeef),
544 m2a,
Joe Tsaif0c01e42018-11-06 13:05:20 -0800545 &[]bool{true},
546 &[]int32{-1000},
547 &[]uint32{1280},
548 &[]float32{1.6180},
549 &[]string{"zero"},
550 &[][]byte{[]byte("zero")},
551 &[]proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO},
Joe Tsai87b955b2018-11-14 21:59:49 -0800552 &[]*proto2_20180125.Message_ChildMessage{m1b},
553 &[]EnumProto2{0xdead},
554 &[]*EnumMessages{m2b},
Joe Tsaif0c01e42018-11-06 13:05:20 -0800555 }
Joe Tsai08e00302018-11-26 22:32:06 -0800556 for i, xt := range extensionTypes {
Joe Tsai0fc49f82019-05-01 12:29:25 -0700557 fs.Set(xt.Descriptor().Number(), xt.ValueOf(setValues[i]))
Joe Tsaif0c01e42018-11-06 13:05:20 -0800558 }
Joe Tsai08e00302018-11-26 22:32:06 -0800559 for i, xt := range extensionTypes[len(extensionTypes)/2:] {
560 v := extensionTypes[i].ValueOf(setValues[i])
Joe Tsai0fc49f82019-05-01 12:29:25 -0700561 fs.Get(xt.Descriptor().Number()).List().Append(v)
Joe Tsaif0c01e42018-11-06 13:05:20 -0800562 }
563
564 // Get the values and check for equality.
565 getValues := []interface{}{
566 bool(false),
567 int32(-54321),
568 uint32(6400),
569 float32(2.71828),
570 string("goodbye, \"world!\"\n"),
571 []byte("live\xde\xad\xbe\xefchicken"),
572 proto2_20180125.Message_ChildEnum(proto2_20180125.Message_CHARLIE),
Joe Tsai87b955b2018-11-14 21:59:49 -0800573 m1a,
574 EnumProto2(0xbeef),
575 m2a,
Joe Tsaif0c01e42018-11-06 13:05:20 -0800576 &[]bool{true, false},
577 &[]int32{-1000, -54321},
578 &[]uint32{1280, 6400},
579 &[]float32{1.6180, 2.71828},
580 &[]string{"zero", "goodbye, \"world!\"\n"},
581 &[][]byte{[]byte("zero"), []byte("live\xde\xad\xbe\xefchicken")},
582 &[]proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO, proto2_20180125.Message_CHARLIE},
Joe Tsai87b955b2018-11-14 21:59:49 -0800583 &[]*proto2_20180125.Message_ChildMessage{m1b, m1a},
584 &[]EnumProto2{0xdead, 0xbeef},
585 &[]*EnumMessages{m2b, m2a},
Joe Tsaif0c01e42018-11-06 13:05:20 -0800586 }
Joe Tsai08e00302018-11-26 22:32:06 -0800587 for i, xt := range extensionTypes {
Joe Tsai0fc49f82019-05-01 12:29:25 -0700588 num := xt.Descriptor().Number()
589 got := xt.InterfaceOf(fs.Get(num))
Joe Tsaif0c01e42018-11-06 13:05:20 -0800590 want := getValues[i]
591 if diff := cmp.Diff(want, got, opts); diff != "" {
Joe Tsai0fc49f82019-05-01 12:29:25 -0700592 t.Errorf("KnownFields.Get(%d) mismatch (-want +got):\n%v", num, diff)
Joe Tsaif0c01e42018-11-06 13:05:20 -0800593 }
594 }
595
Joe Tsai87b955b2018-11-14 21:59:49 -0800596 if n := fs.Len(); n != 20 {
Joe Tsaif0c01e42018-11-06 13:05:20 -0800597 t.Errorf("KnownFields.Len() = %v, want 0", n)
598 }
Joe Tsai87b955b2018-11-14 21:59:49 -0800599 if n := ts.Len(); n != 20 {
600 t.Errorf("ExtensionFieldTypes.Len() = %v, want 20", n)
Joe Tsaif0c01e42018-11-06 13:05:20 -0800601 }
602
603 // Clear the field for all extension types.
Joe Tsai08e00302018-11-26 22:32:06 -0800604 for _, xt := range extensionTypes[:len(extensionTypes)/2] {
Joe Tsai0fc49f82019-05-01 12:29:25 -0700605 fs.Clear(xt.Descriptor().Number())
Joe Tsaif0c01e42018-11-06 13:05:20 -0800606 }
Joe Tsai08e00302018-11-26 22:32:06 -0800607 for i, xt := range extensionTypes[len(extensionTypes)/2:] {
Joe Tsaif6d4a422018-11-19 14:26:06 -0800608 if i%2 == 0 {
Joe Tsai0fc49f82019-05-01 12:29:25 -0700609 fs.Clear(xt.Descriptor().Number())
Joe Tsaif6d4a422018-11-19 14:26:06 -0800610 } else {
Joe Tsai0fc49f82019-05-01 12:29:25 -0700611 fs.Get(xt.Descriptor().Number()).List().Truncate(0)
Joe Tsaif6d4a422018-11-19 14:26:06 -0800612 }
613 }
Joe Tsaif0c01e42018-11-06 13:05:20 -0800614 if n := fs.Len(); n != 0 {
615 t.Errorf("KnownFields.Len() = %v, want 0", n)
616 }
Joe Tsai87b955b2018-11-14 21:59:49 -0800617 if n := ts.Len(); n != 20 {
618 t.Errorf("ExtensionFieldTypes.Len() = %v, want 20", n)
Joe Tsaif0c01e42018-11-06 13:05:20 -0800619 }
620
621 // De-register all extension types.
Joe Tsai08e00302018-11-26 22:32:06 -0800622 for _, xt := range extensionTypes {
Joe Tsaif0c01e42018-11-06 13:05:20 -0800623 ts.Remove(xt)
624 }
625 if n := fs.Len(); n != 0 {
626 t.Errorf("KnownFields.Len() = %v, want 0", n)
627 }
628 if n := ts.Len(); n != 0 {
629 t.Errorf("ExtensionFieldTypes.Len() = %v, want 0", n)
630 }
Joe Tsai08e00302018-11-26 22:32:06 -0800631}
Joe Tsaif0c01e42018-11-06 13:05:20 -0800632
Joe Tsai08e00302018-11-26 22:32:06 -0800633func TestExtensionConvert(t *testing.T) {
634 for i := range extensionTypes {
635 i := i
636 t.Run("", func(t *testing.T) {
637 t.Parallel()
638
639 wantType := extensionTypes[i]
640 wantDesc := extensionDescs[i]
Joe Tsai21ade492019-05-22 13:42:54 -0400641 gotType := pimpl.Export{}.ExtensionTypeFromDesc(wantDesc)
642 gotDesc := pimpl.Export{}.ExtensionDescFromType(wantType)
Joe Tsai08e00302018-11-26 22:32:06 -0800643
644 // TODO: We need a test package to compare descriptors.
645 type list interface {
646 Len() int
647 pragma.DoNotImplement
648 }
649 opts := cmp.Options{
650 cmp.Comparer(func(x, y reflect.Type) bool {
651 return x == y
652 }),
653 cmp.Transformer("", func(x list) []interface{} {
654 out := make([]interface{}, x.Len())
655 v := reflect.ValueOf(x)
656 for i := 0; i < x.Len(); i++ {
657 m := v.MethodByName("Get")
658 out[i] = m.Call([]reflect.Value{reflect.ValueOf(i)})[0].Interface()
659 }
660 return out
661 }),
Joe Tsai0fc49f82019-05-01 12:29:25 -0700662 // TODO: Add this when ExtensionType no longer implements
663 // ExtensionDescriptor.
664 /*
665 cmp.Transformer("", func(x pref.ExtensionType) pref.ExtensionDescriptor {
666 return x.Descriptor()
667 }),
668 */
Joe Tsai08e00302018-11-26 22:32:06 -0800669 cmp.Transformer("", func(x pref.Descriptor) map[string]interface{} {
670 out := make(map[string]interface{})
671 v := reflect.ValueOf(x)
672 for i := 0; i < v.NumMethod(); i++ {
673 name := v.Type().Method(i).Name
674 if m := v.Method(i); m.Type().NumIn() == 0 && m.Type().NumOut() == 1 {
675 switch name {
676 case "New":
677 // Ignore New since it a constructor.
678 case "Options":
679 // Ignore descriptor options since protos are not cmperable.
Joe Tsaiac31a352019-05-13 14:32:56 -0700680 case "ContainingOneof", "ContainingMessage", "Enum", "Message":
Joe Tsai08e00302018-11-26 22:32:06 -0800681 // Avoid descending into a dependency to avoid a cycle.
682 // Just record the full name if available.
683 //
684 // TODO: Cycle support in cmp would be useful here.
685 v := m.Call(nil)[0]
686 if !v.IsNil() {
687 out[name] = v.Interface().(pref.Descriptor).FullName()
688 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700689 case "Oneof", "Extendee":
690 // TODO: Remove this.
Joe Tsai08e00302018-11-26 22:32:06 -0800691 default:
692 out[name] = m.Call(nil)[0].Interface()
693 }
694 }
695 }
696 return out
697 }),
698 cmp.Transformer("", func(v pref.Value) interface{} {
699 return v.Interface()
700 }),
701 }
702 if diff := cmp.Diff(&wantType, &gotType, opts); diff != "" {
703 t.Errorf("ExtensionType mismatch (-want, +got):\n%v", diff)
704 }
705
706 opts = cmp.Options{
Joe Tsai4fddeba2019-03-20 18:29:32 -0700707 cmpopts.IgnoreFields(piface.ExtensionDescV1{}, "Type"),
Joe Tsai08e00302018-11-26 22:32:06 -0800708 }
709 if diff := cmp.Diff(wantDesc, gotDesc, opts); diff != "" {
710 t.Errorf("ExtensionDesc mismatch (-want, +got):\n%v", diff)
711 }
712 })
713 }
Joe Tsaif0c01e42018-11-06 13:05:20 -0800714}
Joe Tsai21ade492019-05-22 13:42:54 -0400715
716type (
717 MessageA struct {
718 A1 *MessageA `protobuf:"bytes,1,req,name=a1"`
719 A2 *MessageB `protobuf:"bytes,2,req,name=a2"`
720 A3 Enum `protobuf:"varint,3,opt,name=a3,enum=legacy.Enum"`
721 }
722 MessageB struct {
723 B1 *MessageA `protobuf:"bytes,1,req,name=b1"`
724 B2 *MessageB `protobuf:"bytes,2,req,name=b2"`
725 B3 Enum `protobuf:"varint,3,opt,name=b3,enum=legacy.Enum"`
726 }
727 Enum int32
728)
729
730// TestConcurrentInit tests that concurrent wrapping of multiple legacy types
731// results in the exact same descriptor being created.
732func TestConcurrentInit(t *testing.T) {
733 const numParallel = 5
734 var messageATypes [numParallel]pref.MessageType
735 var messageBTypes [numParallel]pref.MessageType
736 var enumDescs [numParallel]pref.EnumDescriptor
737
738 // Concurrently load message and enum types.
739 var wg sync.WaitGroup
740 for i := 0; i < numParallel; i++ {
741 i := i
742 wg.Add(3)
743 go func() {
744 defer wg.Done()
745 messageATypes[i] = pimpl.Export{}.MessageTypeOf((*MessageA)(nil))
746 }()
747 go func() {
748 defer wg.Done()
749 messageBTypes[i] = pimpl.Export{}.MessageTypeOf((*MessageB)(nil))
750 }()
751 go func() {
752 defer wg.Done()
753 enumDescs[i] = pimpl.Export{}.EnumDescriptorOf(Enum(0))
754 }()
755 }
756 wg.Wait()
757
758 var (
759 wantMTA = messageATypes[0]
760 wantMDA = messageATypes[0].Descriptor().Fields().ByNumber(1).Message()
761 wantMTB = messageBTypes[0]
762 wantMDB = messageBTypes[0].Descriptor().Fields().ByNumber(2).Message()
763 wantED = messageATypes[0].Descriptor().Fields().ByNumber(3).Enum()
764 )
765
766 for _, gotMT := range messageATypes[1:] {
767 if gotMT != wantMTA {
768 t.Error("MessageType(MessageA) mismatch")
769 }
770 if gotMDA := gotMT.Descriptor().Fields().ByNumber(1).Message(); gotMDA != wantMDA {
771 t.Error("MessageDescriptor(MessageA) mismatch")
772 }
773 if gotMDB := gotMT.Descriptor().Fields().ByNumber(2).Message(); gotMDB != wantMDB {
774 t.Error("MessageDescriptor(MessageB) mismatch")
775 }
776 if gotED := gotMT.Descriptor().Fields().ByNumber(3).Enum(); gotED != wantED {
777 t.Error("EnumDescriptor(Enum) mismatch")
778 }
779 }
780 for _, gotMT := range messageBTypes[1:] {
781 if gotMT != wantMTB {
782 t.Error("MessageType(MessageB) mismatch")
783 }
784 if gotMDA := gotMT.Descriptor().Fields().ByNumber(1).Message(); gotMDA != wantMDA {
785 t.Error("MessageDescriptor(MessageA) mismatch")
786 }
787 if gotMDB := gotMT.Descriptor().Fields().ByNumber(2).Message(); gotMDB != wantMDB {
788 t.Error("MessageDescriptor(MessageB) mismatch")
789 }
790 if gotED := gotMT.Descriptor().Fields().ByNumber(3).Enum(); gotED != wantED {
791 t.Error("EnumDescriptor(Enum) mismatch")
792 }
793 }
794 for _, gotED := range enumDescs[1:] {
795 if gotED != wantED {
796 t.Error("EnumType(Enum) mismatch")
797 }
798 }
799}