blob: 1bc5acff4af2cc21cdf40b780adf4e5c4e23296f [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"
11 "testing"
12
Joe Tsaiea118132018-11-11 17:56:21 -080013 pack "github.com/golang/protobuf/v2/internal/encoding/pack"
Joe Tsai08e00302018-11-26 22:32:06 -080014 pimpl "github.com/golang/protobuf/v2/internal/impl"
Joe Tsaiea118132018-11-11 17:56:21 -080015 pragma "github.com/golang/protobuf/v2/internal/pragma"
Joe Tsai990b9f52019-03-13 12:56:39 -070016 ptype "github.com/golang/protobuf/v2/internal/prototype"
Joe Tsai009e0672018-11-27 18:45:07 -080017 scalar "github.com/golang/protobuf/v2/internal/scalar"
Joe Tsai90fe9962018-10-18 11:06:29 -070018 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
Joe Tsai4fddeba2019-03-20 18:29:32 -070019 piface "github.com/golang/protobuf/v2/runtime/protoiface"
Joe Tsaiea118132018-11-11 17:56:21 -080020 cmp "github.com/google/go-cmp/cmp"
Joe Tsai08e00302018-11-26 22:32:06 -080021 cmpopts "github.com/google/go-cmp/cmp/cmpopts"
Joe Tsaiea118132018-11-11 17:56:21 -080022
Joe Tsai08e00302018-11-26 22:32:06 -080023 // The legacy package must be imported prior to use of any legacy messages.
24 // TODO: Remove this when protoV1 registers these hooks for you.
25 plegacy "github.com/golang/protobuf/v2/internal/legacy"
26
Joe Tsaiea118132018-11-11 17:56:21 -080027 proto2_20180125 "github.com/golang/protobuf/v2/internal/testprotos/legacy/proto2.v1.0.0-20180125-92554152"
Joe Tsai90fe9962018-10-18 11:06:29 -070028)
29
Joe Tsaif0c01e42018-11-06 13:05:20 -080030type legacyTestMessage struct {
Joe Tsai4fddeba2019-03-20 18:29:32 -070031 XXX_unrecognized []byte
32 XXX_InternalExtensions pimpl.ExtensionFieldsV1
Joe Tsai95b02902018-10-31 18:23:42 -070033}
34
Joe Tsaif0c01e42018-11-06 13:05:20 -080035func (*legacyTestMessage) Reset() {}
36func (*legacyTestMessage) String() string { return "" }
37func (*legacyTestMessage) ProtoMessage() {}
Joe Tsai4fddeba2019-03-20 18:29:32 -070038func (*legacyTestMessage) ExtensionRangeArray() []piface.ExtensionRangeV1 {
39 return []piface.ExtensionRangeV1{{Start: 10, End: 20}, {Start: 40, End: 80}, {Start: 10000, End: 20000}}
Joe Tsai95b02902018-10-31 18:23:42 -070040}
41
Joe Tsaie2afdc22018-10-25 14:06:56 -070042func TestLegacyUnknown(t *testing.T) {
43 rawOf := func(toks ...pack.Token) pref.RawFields {
44 return pref.RawFields(pack.Message(toks).Marshal())
45 }
46 raw1a := rawOf(pack.Tag{1, pack.VarintType}, pack.Svarint(-4321)) // 08c143
47 raw1b := rawOf(pack.Tag{1, pack.Fixed32Type}, pack.Uint32(0xdeadbeef)) // 0defbeadde
48 raw1c := rawOf(pack.Tag{1, pack.Fixed64Type}, pack.Float64(math.Pi)) // 09182d4454fb210940
49 raw2a := rawOf(pack.Tag{2, pack.BytesType}, pack.String("hello, world!")) // 120d68656c6c6f2c20776f726c6421
50 raw2b := rawOf(pack.Tag{2, pack.VarintType}, pack.Uvarint(1234)) // 10d209
51 raw3a := rawOf(pack.Tag{3, pack.StartGroupType}, pack.Tag{3, pack.EndGroupType}) // 1b1c
52 raw3b := rawOf(pack.Tag{3, pack.BytesType}, pack.Bytes("\xde\xad\xbe\xef")) // 1a04deadbeef
53
Joe Tsai95b02902018-10-31 18:23:42 -070054 raw1 := rawOf(pack.Tag{1, pack.BytesType}, pack.Bytes("1")) // 0a0131
55 raw3 := rawOf(pack.Tag{3, pack.BytesType}, pack.Bytes("3")) // 1a0133
56 raw10 := rawOf(pack.Tag{10, pack.BytesType}, pack.Bytes("10")) // 52023130 - extension
57 raw15 := rawOf(pack.Tag{15, pack.BytesType}, pack.Bytes("15")) // 7a023135 - extension
58 raw26 := rawOf(pack.Tag{26, pack.BytesType}, pack.Bytes("26")) // d201023236
59 raw32 := rawOf(pack.Tag{32, pack.BytesType}, pack.Bytes("32")) // 8202023332
60 raw45 := rawOf(pack.Tag{45, pack.BytesType}, pack.Bytes("45")) // ea02023435 - extension
61 raw46 := rawOf(pack.Tag{45, pack.BytesType}, pack.Bytes("46")) // ea02023436 - extension
62 raw47 := rawOf(pack.Tag{45, pack.BytesType}, pack.Bytes("47")) // ea02023437 - extension
63 raw99 := rawOf(pack.Tag{99, pack.BytesType}, pack.Bytes("99")) // 9a06023939
64
Joe Tsaie2afdc22018-10-25 14:06:56 -070065 joinRaw := func(bs ...pref.RawFields) (out []byte) {
66 for _, b := range bs {
67 out = append(out, b...)
68 }
69 return out
70 }
71
Joe Tsaif0c01e42018-11-06 13:05:20 -080072 m := new(legacyTestMessage)
Joe Tsai08e00302018-11-26 22:32:06 -080073 fs := pimpl.Export{}.MessageOf(m).UnknownFields()
Joe Tsai95b02902018-10-31 18:23:42 -070074
Joe Tsaie2afdc22018-10-25 14:06:56 -070075 if got, want := fs.Len(), 0; got != want {
76 t.Errorf("Len() = %d, want %d", got, want)
77 }
Joe Tsai95b02902018-10-31 18:23:42 -070078 if got, want := m.XXX_unrecognized, joinRaw(); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -070079 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
80 }
81
82 fs.Set(1, raw1a)
83 fs.Set(1, append(fs.Get(1), raw1b...))
84 fs.Set(1, append(fs.Get(1), raw1c...))
85 if got, want := fs.Len(), 1; got != want {
86 t.Errorf("Len() = %d, want %d", got, want)
87 }
Joe Tsai95b02902018-10-31 18:23:42 -070088 if got, want := m.XXX_unrecognized, joinRaw(raw1a, raw1b, raw1c); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -070089 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
90 }
91
92 fs.Set(2, raw2a)
93 if got, want := fs.Len(), 2; got != want {
94 t.Errorf("Len() = %d, want %d", got, want)
95 }
Joe Tsai95b02902018-10-31 18:23:42 -070096 if got, want := m.XXX_unrecognized, joinRaw(raw1a, raw1b, raw1c, raw2a); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -070097 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
98 }
99
100 if got, want := fs.Get(1), joinRaw(raw1a, raw1b, raw1c); !bytes.Equal(got, want) {
101 t.Errorf("Get(%d) = %x, want %x", 1, got, want)
102 }
103 if got, want := fs.Get(2), joinRaw(raw2a); !bytes.Equal(got, want) {
104 t.Errorf("Get(%d) = %x, want %x", 2, got, want)
105 }
106 if got, want := fs.Get(3), joinRaw(); !bytes.Equal(got, want) {
107 t.Errorf("Get(%d) = %x, want %x", 3, got, want)
108 }
109
110 fs.Set(1, nil) // remove field 1
111 if got, want := fs.Len(), 1; got != want {
112 t.Errorf("Len() = %d, want %d", got, want)
113 }
Joe Tsai95b02902018-10-31 18:23:42 -0700114 if got, want := m.XXX_unrecognized, joinRaw(raw2a); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -0700115 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
116 }
117
118 // Simulate manual appending of raw field data.
Joe Tsai95b02902018-10-31 18:23:42 -0700119 m.XXX_unrecognized = append(m.XXX_unrecognized, joinRaw(raw3a, raw1a, raw1b, raw2b, raw3b, raw1c)...)
Joe Tsaie2afdc22018-10-25 14:06:56 -0700120 if got, want := fs.Len(), 3; got != want {
121 t.Errorf("Len() = %d, want %d", got, want)
122 }
123
124 // Verify range iteration order.
125 var i int
126 want := []struct {
127 num pref.FieldNumber
128 raw pref.RawFields
129 }{
Joe Tsaie2afdc22018-10-25 14:06:56 -0700130 {2, joinRaw(raw2a, raw2b)},
Joe Tsai2d5a1692018-10-29 02:10:42 -0700131 {3, joinRaw(raw3a, raw3b)},
Joe Tsaie2afdc22018-10-25 14:06:56 -0700132 {1, joinRaw(raw1a, raw1b, raw1c)},
133 }
134 fs.Range(func(num pref.FieldNumber, raw pref.RawFields) bool {
135 if i < len(want) {
136 if num != want[i].num || !bytes.Equal(raw, want[i].raw) {
137 t.Errorf("Range(%d) = (%d, %x), want (%d, %x)", i, num, raw, want[i].num, want[i].raw)
138 }
139 } else {
140 t.Errorf("unexpected Range iteration: %d", i)
141 }
142 i++
143 return true
144 })
145
146 fs.Set(2, fs.Get(2)) // moves field 2 to the end
147 if got, want := fs.Len(), 3; 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, raw1a, raw1b, raw3b, raw1c, 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 fs.Set(1, nil) // remove field 1
154 if got, want := fs.Len(), 2; got != want {
155 t.Errorf("Len() = %d, want %d", got, want)
156 }
Joe Tsai95b02902018-10-31 18:23:42 -0700157 if got, want := m.XXX_unrecognized, joinRaw(raw3a, raw3b, raw2a, raw2b); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -0700158 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
159 }
160
161 // Remove all fields.
162 fs.Range(func(n pref.FieldNumber, b pref.RawFields) bool {
163 fs.Set(n, nil)
164 return true
165 })
166 if got, want := fs.Len(), 0; got != want {
167 t.Errorf("Len() = %d, want %d", got, want)
168 }
Joe Tsai95b02902018-10-31 18:23:42 -0700169 if got, want := m.XXX_unrecognized, joinRaw(); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -0700170 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
171 }
Joe Tsai95b02902018-10-31 18:23:42 -0700172
173 fs.Set(1, raw1)
174 if got, want := fs.Len(), 1; got != want {
175 t.Errorf("Len() = %d, want %d", got, want)
176 }
177 if got, want := m.XXX_unrecognized, joinRaw(raw1); !bytes.Equal(got, want) {
178 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
179 }
180
181 fs.Set(45, raw45)
182 fs.Set(10, raw10) // extension
183 fs.Set(32, raw32)
184 fs.Set(1, nil) // deletion
185 fs.Set(26, raw26)
186 fs.Set(47, raw47) // extension
187 fs.Set(46, raw46) // extension
188 if got, want := fs.Len(), 6; got != want {
189 t.Errorf("Len() = %d, want %d", got, want)
190 }
191 if got, want := m.XXX_unrecognized, joinRaw(raw32, raw26); !bytes.Equal(got, want) {
192 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
193 }
194
195 // Verify iteration order.
196 i = 0
197 want = []struct {
198 num pref.FieldNumber
199 raw pref.RawFields
200 }{
201 {32, raw32},
202 {26, raw26},
203 {10, raw10}, // extension
204 {45, raw45}, // extension
205 {46, raw46}, // extension
206 {47, raw47}, // extension
207 }
208 fs.Range(func(num pref.FieldNumber, raw pref.RawFields) bool {
209 if i < len(want) {
210 if num != want[i].num || !bytes.Equal(raw, want[i].raw) {
211 t.Errorf("Range(%d) = (%d, %x), want (%d, %x)", i, num, raw, want[i].num, want[i].raw)
212 }
213 } else {
214 t.Errorf("unexpected Range iteration: %d", i)
215 }
216 i++
217 return true
218 })
219
220 // Perform partial deletion while iterating.
221 i = 0
222 fs.Range(func(num pref.FieldNumber, raw pref.RawFields) bool {
223 if i%2 == 0 {
224 fs.Set(num, nil)
225 }
226 i++
227 return true
228 })
229
230 if got, want := fs.Len(), 3; got != want {
231 t.Errorf("Len() = %d, want %d", got, want)
232 }
233 if got, want := m.XXX_unrecognized, joinRaw(raw26); !bytes.Equal(got, want) {
234 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
235 }
236
237 fs.Set(15, raw15) // extension
238 fs.Set(3, raw3)
239 fs.Set(99, raw99)
240 if got, want := fs.Len(), 6; got != want {
241 t.Errorf("Len() = %d, want %d", got, want)
242 }
243 if got, want := m.XXX_unrecognized, joinRaw(raw26, raw3, raw99); !bytes.Equal(got, want) {
244 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
245 }
246
247 // Perform partial iteration.
248 i = 0
249 want = []struct {
250 num pref.FieldNumber
251 raw pref.RawFields
252 }{
253 {26, raw26},
254 {3, raw3},
255 }
256 fs.Range(func(num pref.FieldNumber, raw pref.RawFields) bool {
257 if i < len(want) {
258 if num != want[i].num || !bytes.Equal(raw, want[i].raw) {
259 t.Errorf("Range(%d) = (%d, %x), want (%d, %x)", i, num, raw, want[i].num, want[i].raw)
260 }
261 } else {
262 t.Errorf("unexpected Range iteration: %d", i)
263 }
264 i++
265 return i < 2
266 })
Joe Tsaie2afdc22018-10-25 14:06:56 -0700267}
Joe Tsaif0c01e42018-11-06 13:05:20 -0800268
Joe Tsai08e00302018-11-26 22:32:06 -0800269func mustMakeExtensionType(x *ptype.StandaloneExtension, v interface{}) pref.ExtensionType {
270 xd, err := ptype.NewExtension(x)
271 if err != nil {
272 panic(xd)
Joe Tsaif0c01e42018-11-06 13:05:20 -0800273 }
Joe Tsai08e00302018-11-26 22:32:06 -0800274 return pimpl.Export{}.ExtensionTypeOf(xd, v)
275}
276
277var (
278 parentType = pimpl.Export{}.MessageTypeOf((*legacyTestMessage)(nil))
279 enumV1Type = pimpl.Export{}.EnumTypeOf(proto2_20180125.Message_ChildEnum(0))
280 messageV1Type = pimpl.Export{}.MessageTypeOf((*proto2_20180125.Message_ChildMessage)(nil))
281 enumV2Type = enumProto2Type
Damien Neil8012b442019-01-18 09:32:24 -0800282 messageV2Type = enumMessagesType.PBType
Joe Tsai08e00302018-11-26 22:32:06 -0800283
284 extensionTypes = []pref.ExtensionType{
285 mustMakeExtensionType(&ptype.StandaloneExtension{
286 FullName: "fizz.buzz.optional_bool",
287 Number: 10000,
288 Cardinality: pref.Optional,
289 Kind: pref.BoolKind,
290 Default: pref.ValueOf(true),
291 ExtendedType: parentType,
292 }, nil),
293 mustMakeExtensionType(&ptype.StandaloneExtension{
294 FullName: "fizz.buzz.optional_int32",
295 Number: 10001,
296 Cardinality: pref.Optional,
297 Kind: pref.Int32Kind,
298 Default: pref.ValueOf(int32(-12345)),
299 ExtendedType: parentType,
300 }, nil),
301 mustMakeExtensionType(&ptype.StandaloneExtension{
302 FullName: "fizz.buzz.optional_uint32",
303 Number: 10002,
304 Cardinality: pref.Optional,
305 Kind: pref.Uint32Kind,
306 Default: pref.ValueOf(uint32(3200)),
307 ExtendedType: parentType,
308 }, nil),
309 mustMakeExtensionType(&ptype.StandaloneExtension{
310 FullName: "fizz.buzz.optional_float",
311 Number: 10003,
312 Cardinality: pref.Optional,
313 Kind: pref.FloatKind,
314 Default: pref.ValueOf(float32(3.14159)),
315 ExtendedType: parentType,
316 }, nil),
317 mustMakeExtensionType(&ptype.StandaloneExtension{
318 FullName: "fizz.buzz.optional_string",
319 Number: 10004,
320 Cardinality: pref.Optional,
321 Kind: pref.StringKind,
322 Default: pref.ValueOf(string("hello, \"world!\"\n")),
323 ExtendedType: parentType,
324 }, nil),
325 mustMakeExtensionType(&ptype.StandaloneExtension{
326 FullName: "fizz.buzz.optional_bytes",
327 Number: 10005,
328 Cardinality: pref.Optional,
329 Kind: pref.BytesKind,
330 Default: pref.ValueOf([]byte("dead\xde\xad\xbe\xefbeef")),
331 ExtendedType: parentType,
332 }, nil),
333 mustMakeExtensionType(&ptype.StandaloneExtension{
334 FullName: "fizz.buzz.optional_enum_v1",
335 Number: 10006,
336 Cardinality: pref.Optional,
337 Kind: pref.EnumKind,
338 Default: pref.ValueOf(pref.EnumNumber(0)),
339 EnumType: enumV1Type,
340 ExtendedType: parentType,
341 }, proto2_20180125.Message_ChildEnum(0)),
342 mustMakeExtensionType(&ptype.StandaloneExtension{
343 FullName: "fizz.buzz.optional_message_v1",
344 Number: 10007,
345 Cardinality: pref.Optional,
346 Kind: pref.MessageKind,
347 MessageType: messageV1Type,
348 ExtendedType: parentType,
349 }, (*proto2_20180125.Message_ChildMessage)(nil)),
350 mustMakeExtensionType(&ptype.StandaloneExtension{
351 FullName: "fizz.buzz.optional_enum_v2",
352 Number: 10008,
353 Cardinality: pref.Optional,
354 Kind: pref.EnumKind,
355 Default: pref.ValueOf(pref.EnumNumber(57005)),
356 EnumType: enumV2Type,
357 ExtendedType: parentType,
358 }, EnumProto2(0)),
359 mustMakeExtensionType(&ptype.StandaloneExtension{
360 FullName: "fizz.buzz.optional_message_v2",
361 Number: 10009,
362 Cardinality: pref.Optional,
363 Kind: pref.MessageKind,
364 MessageType: messageV2Type,
365 ExtendedType: parentType,
366 }, (*EnumMessages)(nil)),
367 mustMakeExtensionType(&ptype.StandaloneExtension{
368 FullName: "fizz.buzz.repeated_bool",
369 Number: 10010,
370 Cardinality: pref.Repeated,
371 Kind: pref.BoolKind,
372 ExtendedType: parentType,
373 }, nil),
374 mustMakeExtensionType(&ptype.StandaloneExtension{
375 FullName: "fizz.buzz.repeated_int32",
376 Number: 10011,
377 Cardinality: pref.Repeated,
378 Kind: pref.Int32Kind,
379 ExtendedType: parentType,
380 }, nil),
381 mustMakeExtensionType(&ptype.StandaloneExtension{
382 FullName: "fizz.buzz.repeated_uint32",
383 Number: 10012,
384 Cardinality: pref.Repeated,
385 Kind: pref.Uint32Kind,
386 ExtendedType: parentType,
387 }, nil),
388 mustMakeExtensionType(&ptype.StandaloneExtension{
389 FullName: "fizz.buzz.repeated_float",
390 Number: 10013,
391 Cardinality: pref.Repeated,
392 Kind: pref.FloatKind,
393 ExtendedType: parentType,
394 }, nil),
395 mustMakeExtensionType(&ptype.StandaloneExtension{
396 FullName: "fizz.buzz.repeated_string",
397 Number: 10014,
398 Cardinality: pref.Repeated,
399 Kind: pref.StringKind,
400 ExtendedType: parentType,
401 }, nil),
402 mustMakeExtensionType(&ptype.StandaloneExtension{
403 FullName: "fizz.buzz.repeated_bytes",
404 Number: 10015,
405 Cardinality: pref.Repeated,
406 Kind: pref.BytesKind,
407 ExtendedType: parentType,
408 }, nil),
409 mustMakeExtensionType(&ptype.StandaloneExtension{
410 FullName: "fizz.buzz.repeated_enum_v1",
411 Number: 10016,
412 Cardinality: pref.Repeated,
413 Kind: pref.EnumKind,
414 EnumType: enumV1Type,
415 ExtendedType: parentType,
416 }, proto2_20180125.Message_ChildEnum(0)),
417 mustMakeExtensionType(&ptype.StandaloneExtension{
418 FullName: "fizz.buzz.repeated_message_v1",
419 Number: 10017,
420 Cardinality: pref.Repeated,
421 Kind: pref.MessageKind,
422 MessageType: messageV1Type,
423 ExtendedType: parentType,
424 }, (*proto2_20180125.Message_ChildMessage)(nil)),
425 mustMakeExtensionType(&ptype.StandaloneExtension{
426 FullName: "fizz.buzz.repeated_enum_v2",
427 Number: 10018,
428 Cardinality: pref.Repeated,
429 Kind: pref.EnumKind,
430 EnumType: enumV2Type,
431 ExtendedType: parentType,
432 }, EnumProto2(0)),
433 mustMakeExtensionType(&ptype.StandaloneExtension{
434 FullName: "fizz.buzz.repeated_message_v2",
435 Number: 10019,
436 Cardinality: pref.Repeated,
437 Kind: pref.MessageKind,
438 MessageType: messageV2Type,
439 ExtendedType: parentType,
440 }, (*EnumMessages)(nil)),
441 }
442
Joe Tsai4fddeba2019-03-20 18:29:32 -0700443 extensionDescs = []*piface.ExtensionDescV1{{
Joe Tsai08e00302018-11-26 22:32:06 -0800444 ExtendedType: (*legacyTestMessage)(nil),
445 ExtensionType: (*bool)(nil),
446 Field: 10000,
447 Name: "fizz.buzz.optional_bool",
448 Tag: "varint,10000,opt,name=optional_bool,def=1",
449 }, {
450 ExtendedType: (*legacyTestMessage)(nil),
451 ExtensionType: (*int32)(nil),
452 Field: 10001,
453 Name: "fizz.buzz.optional_int32",
454 Tag: "varint,10001,opt,name=optional_int32,def=-12345",
455 }, {
456 ExtendedType: (*legacyTestMessage)(nil),
457 ExtensionType: (*uint32)(nil),
458 Field: 10002,
459 Name: "fizz.buzz.optional_uint32",
460 Tag: "varint,10002,opt,name=optional_uint32,def=3200",
461 }, {
462 ExtendedType: (*legacyTestMessage)(nil),
463 ExtensionType: (*float32)(nil),
464 Field: 10003,
465 Name: "fizz.buzz.optional_float",
466 Tag: "fixed32,10003,opt,name=optional_float,def=3.14159",
467 }, {
468 ExtendedType: (*legacyTestMessage)(nil),
469 ExtensionType: (*string)(nil),
470 Field: 10004,
471 Name: "fizz.buzz.optional_string",
472 Tag: "bytes,10004,opt,name=optional_string,def=hello, \"world!\"\n",
473 }, {
474 ExtendedType: (*legacyTestMessage)(nil),
475 ExtensionType: ([]byte)(nil),
476 Field: 10005,
477 Name: "fizz.buzz.optional_bytes",
478 Tag: "bytes,10005,opt,name=optional_bytes,def=dead\\336\\255\\276\\357beef",
479 }, {
480 ExtendedType: (*legacyTestMessage)(nil),
481 ExtensionType: (*proto2_20180125.Message_ChildEnum)(nil),
482 Field: 10006,
483 Name: "fizz.buzz.optional_enum_v1",
484 Tag: "varint,10006,opt,name=optional_enum_v1,enum=google.golang.org.proto2_20180125.Message_ChildEnum,def=0",
485 }, {
486 ExtendedType: (*legacyTestMessage)(nil),
487 ExtensionType: (*proto2_20180125.Message_ChildMessage)(nil),
488 Field: 10007,
489 Name: "fizz.buzz.optional_message_v1",
490 Tag: "bytes,10007,opt,name=optional_message_v1",
491 }, {
492 ExtendedType: (*legacyTestMessage)(nil),
493 ExtensionType: (*EnumProto2)(nil),
494 Field: 10008,
495 Name: "fizz.buzz.optional_enum_v2",
496 Tag: "varint,10008,opt,name=optional_enum_v2,enum=EnumProto2,def=57005",
497 }, {
498 ExtendedType: (*legacyTestMessage)(nil),
499 ExtensionType: (*EnumMessages)(nil),
500 Field: 10009,
501 Name: "fizz.buzz.optional_message_v2",
502 Tag: "bytes,10009,opt,name=optional_message_v2",
503 }, {
504 ExtendedType: (*legacyTestMessage)(nil),
505 ExtensionType: ([]bool)(nil),
506 Field: 10010,
507 Name: "fizz.buzz.repeated_bool",
508 Tag: "varint,10010,rep,name=repeated_bool",
509 }, {
510 ExtendedType: (*legacyTestMessage)(nil),
511 ExtensionType: ([]int32)(nil),
512 Field: 10011,
513 Name: "fizz.buzz.repeated_int32",
514 Tag: "varint,10011,rep,name=repeated_int32",
515 }, {
516 ExtendedType: (*legacyTestMessage)(nil),
517 ExtensionType: ([]uint32)(nil),
518 Field: 10012,
519 Name: "fizz.buzz.repeated_uint32",
520 Tag: "varint,10012,rep,name=repeated_uint32",
521 }, {
522 ExtendedType: (*legacyTestMessage)(nil),
523 ExtensionType: ([]float32)(nil),
524 Field: 10013,
525 Name: "fizz.buzz.repeated_float",
526 Tag: "fixed32,10013,rep,name=repeated_float",
527 }, {
528 ExtendedType: (*legacyTestMessage)(nil),
529 ExtensionType: ([]string)(nil),
530 Field: 10014,
531 Name: "fizz.buzz.repeated_string",
532 Tag: "bytes,10014,rep,name=repeated_string",
533 }, {
534 ExtendedType: (*legacyTestMessage)(nil),
535 ExtensionType: ([][]byte)(nil),
536 Field: 10015,
537 Name: "fizz.buzz.repeated_bytes",
538 Tag: "bytes,10015,rep,name=repeated_bytes",
539 }, {
540 ExtendedType: (*legacyTestMessage)(nil),
541 ExtensionType: ([]proto2_20180125.Message_ChildEnum)(nil),
542 Field: 10016,
543 Name: "fizz.buzz.repeated_enum_v1",
544 Tag: "varint,10016,rep,name=repeated_enum_v1,enum=google.golang.org.proto2_20180125.Message_ChildEnum",
545 }, {
546 ExtendedType: (*legacyTestMessage)(nil),
547 ExtensionType: ([]*proto2_20180125.Message_ChildMessage)(nil),
548 Field: 10017,
549 Name: "fizz.buzz.repeated_message_v1",
550 Tag: "bytes,10017,rep,name=repeated_message_v1",
551 }, {
552 ExtendedType: (*legacyTestMessage)(nil),
553 ExtensionType: ([]EnumProto2)(nil),
554 Field: 10018,
555 Name: "fizz.buzz.repeated_enum_v2",
556 Tag: "varint,10018,rep,name=repeated_enum_v2,enum=EnumProto2",
557 }, {
558 ExtendedType: (*legacyTestMessage)(nil),
559 ExtensionType: ([]*EnumMessages)(nil),
560 Field: 10019,
561 Name: "fizz.buzz.repeated_message_v2",
562 Tag: "bytes,10019,rep,name=repeated_message_v2",
563 }}
564)
565
566func TestLegacyExtensions(t *testing.T) {
Joe Tsaif0c01e42018-11-06 13:05:20 -0800567 opts := cmp.Options{cmp.Comparer(func(x, y *proto2_20180125.Message_ChildMessage) bool {
568 return x == y // pointer compare messages for object identity
569 })}
570
571 m := new(legacyTestMessage)
Joe Tsai08e00302018-11-26 22:32:06 -0800572 fs := pimpl.Export{}.MessageOf(m).KnownFields()
Joe Tsaif0c01e42018-11-06 13:05:20 -0800573 ts := fs.ExtensionTypes()
574
575 if n := fs.Len(); n != 0 {
576 t.Errorf("KnownFields.Len() = %v, want 0", n)
577 }
578 if n := ts.Len(); n != 0 {
579 t.Errorf("ExtensionFieldTypes.Len() = %v, want 0", n)
580 }
581
582 // Register all the extension types.
Joe Tsai08e00302018-11-26 22:32:06 -0800583 for _, xt := range extensionTypes {
Joe Tsaif0c01e42018-11-06 13:05:20 -0800584 ts.Register(xt)
585 }
586
587 // Check that getting the zero value returns the default value for scalars,
Joe Tsai4b7aff62018-11-14 14:05:19 -0800588 // nil for singular messages, and an empty list for repeated fields.
Joe Tsaif0c01e42018-11-06 13:05:20 -0800589 defaultValues := []interface{}{
590 bool(true),
591 int32(-12345),
592 uint32(3200),
593 float32(3.14159),
594 string("hello, \"world!\"\n"),
595 []byte("dead\xde\xad\xbe\xefbeef"),
596 proto2_20180125.Message_ALPHA,
597 nil,
Joe Tsai87b955b2018-11-14 21:59:49 -0800598 EnumProto2(0xdead),
599 nil,
Joe Tsaif0c01e42018-11-06 13:05:20 -0800600 new([]bool),
601 new([]int32),
602 new([]uint32),
603 new([]float32),
604 new([]string),
605 new([][]byte),
606 new([]proto2_20180125.Message_ChildEnum),
607 new([]*proto2_20180125.Message_ChildMessage),
Joe Tsai87b955b2018-11-14 21:59:49 -0800608 new([]EnumProto2),
609 new([]*EnumMessages),
Joe Tsaif0c01e42018-11-06 13:05:20 -0800610 }
Joe Tsai08e00302018-11-26 22:32:06 -0800611 for i, xt := range extensionTypes {
Joe Tsaif0c01e42018-11-06 13:05:20 -0800612 var got interface{}
Joe Tsaif6d4a422018-11-19 14:26:06 -0800613 if v := fs.Get(xt.Number()); v.IsValid() {
614 got = xt.InterfaceOf(v)
Joe Tsaif0c01e42018-11-06 13:05:20 -0800615 }
616 want := defaultValues[i]
617 if diff := cmp.Diff(want, got, opts); diff != "" {
618 t.Errorf("KnownFields.Get(%d) mismatch (-want +got):\n%v", xt.Number(), diff)
619 }
620 }
621
622 // All fields should be unpopulated.
Joe Tsai08e00302018-11-26 22:32:06 -0800623 for _, xt := range extensionTypes {
Joe Tsaif0c01e42018-11-06 13:05:20 -0800624 if fs.Has(xt.Number()) {
625 t.Errorf("KnownFields.Has(%d) = true, want false", xt.Number())
626 }
627 }
628
Joe Tsai4b7aff62018-11-14 14:05:19 -0800629 // Set some values and append to values to the lists.
Joe Tsai009e0672018-11-27 18:45:07 -0800630 m1a := &proto2_20180125.Message_ChildMessage{F1: scalar.String("m1a")}
631 m1b := &proto2_20180125.Message_ChildMessage{F1: scalar.String("m2b")}
Joe Tsai87b955b2018-11-14 21:59:49 -0800632 m2a := &EnumMessages{EnumP2: EnumProto2(0x1b).Enum()}
633 m2b := &EnumMessages{EnumP2: EnumProto2(0x2b).Enum()}
Joe Tsaif0c01e42018-11-06 13:05:20 -0800634 setValues := []interface{}{
635 bool(false),
636 int32(-54321),
637 uint32(6400),
638 float32(2.71828),
639 string("goodbye, \"world!\"\n"),
640 []byte("live\xde\xad\xbe\xefchicken"),
641 proto2_20180125.Message_CHARLIE,
Joe Tsai87b955b2018-11-14 21:59:49 -0800642 m1a,
643 EnumProto2(0xbeef),
644 m2a,
Joe Tsaif0c01e42018-11-06 13:05:20 -0800645 &[]bool{true},
646 &[]int32{-1000},
647 &[]uint32{1280},
648 &[]float32{1.6180},
649 &[]string{"zero"},
650 &[][]byte{[]byte("zero")},
651 &[]proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO},
Joe Tsai87b955b2018-11-14 21:59:49 -0800652 &[]*proto2_20180125.Message_ChildMessage{m1b},
653 &[]EnumProto2{0xdead},
654 &[]*EnumMessages{m2b},
Joe Tsaif0c01e42018-11-06 13:05:20 -0800655 }
Joe Tsai08e00302018-11-26 22:32:06 -0800656 for i, xt := range extensionTypes {
Joe Tsaif0c01e42018-11-06 13:05:20 -0800657 fs.Set(xt.Number(), xt.ValueOf(setValues[i]))
658 }
Joe Tsai08e00302018-11-26 22:32:06 -0800659 for i, xt := range extensionTypes[len(extensionTypes)/2:] {
660 v := extensionTypes[i].ValueOf(setValues[i])
Joe Tsai4b7aff62018-11-14 14:05:19 -0800661 fs.Get(xt.Number()).List().Append(v)
Joe Tsaif0c01e42018-11-06 13:05:20 -0800662 }
663
664 // Get the values and check for equality.
665 getValues := []interface{}{
666 bool(false),
667 int32(-54321),
668 uint32(6400),
669 float32(2.71828),
670 string("goodbye, \"world!\"\n"),
671 []byte("live\xde\xad\xbe\xefchicken"),
672 proto2_20180125.Message_ChildEnum(proto2_20180125.Message_CHARLIE),
Joe Tsai87b955b2018-11-14 21:59:49 -0800673 m1a,
674 EnumProto2(0xbeef),
675 m2a,
Joe Tsaif0c01e42018-11-06 13:05:20 -0800676 &[]bool{true, false},
677 &[]int32{-1000, -54321},
678 &[]uint32{1280, 6400},
679 &[]float32{1.6180, 2.71828},
680 &[]string{"zero", "goodbye, \"world!\"\n"},
681 &[][]byte{[]byte("zero"), []byte("live\xde\xad\xbe\xefchicken")},
682 &[]proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO, proto2_20180125.Message_CHARLIE},
Joe Tsai87b955b2018-11-14 21:59:49 -0800683 &[]*proto2_20180125.Message_ChildMessage{m1b, m1a},
684 &[]EnumProto2{0xdead, 0xbeef},
685 &[]*EnumMessages{m2b, m2a},
Joe Tsaif0c01e42018-11-06 13:05:20 -0800686 }
Joe Tsai08e00302018-11-26 22:32:06 -0800687 for i, xt := range extensionTypes {
Joe Tsaif0c01e42018-11-06 13:05:20 -0800688 got := xt.InterfaceOf(fs.Get(xt.Number()))
689 want := getValues[i]
690 if diff := cmp.Diff(want, got, opts); diff != "" {
691 t.Errorf("KnownFields.Get(%d) mismatch (-want +got):\n%v", xt.Number(), diff)
692 }
693 }
694
Joe Tsai87b955b2018-11-14 21:59:49 -0800695 if n := fs.Len(); n != 20 {
Joe Tsaif0c01e42018-11-06 13:05:20 -0800696 t.Errorf("KnownFields.Len() = %v, want 0", n)
697 }
Joe Tsai87b955b2018-11-14 21:59:49 -0800698 if n := ts.Len(); n != 20 {
699 t.Errorf("ExtensionFieldTypes.Len() = %v, want 20", n)
Joe Tsaif0c01e42018-11-06 13:05:20 -0800700 }
701
702 // Clear the field for all extension types.
Joe Tsai08e00302018-11-26 22:32:06 -0800703 for _, xt := range extensionTypes[:len(extensionTypes)/2] {
Joe Tsaif0c01e42018-11-06 13:05:20 -0800704 fs.Clear(xt.Number())
705 }
Joe Tsai08e00302018-11-26 22:32:06 -0800706 for i, xt := range extensionTypes[len(extensionTypes)/2:] {
Joe Tsaif6d4a422018-11-19 14:26:06 -0800707 if i%2 == 0 {
708 fs.Clear(xt.Number())
709 } else {
710 fs.Get(xt.Number()).List().Truncate(0)
711 }
712 }
Joe Tsaif0c01e42018-11-06 13:05:20 -0800713 if n := fs.Len(); n != 0 {
714 t.Errorf("KnownFields.Len() = %v, want 0", n)
715 }
Joe Tsai87b955b2018-11-14 21:59:49 -0800716 if n := ts.Len(); n != 20 {
717 t.Errorf("ExtensionFieldTypes.Len() = %v, want 20", n)
Joe Tsaif0c01e42018-11-06 13:05:20 -0800718 }
719
720 // De-register all extension types.
Joe Tsai08e00302018-11-26 22:32:06 -0800721 for _, xt := range extensionTypes {
Joe Tsaif0c01e42018-11-06 13:05:20 -0800722 ts.Remove(xt)
723 }
724 if n := fs.Len(); n != 0 {
725 t.Errorf("KnownFields.Len() = %v, want 0", n)
726 }
727 if n := ts.Len(); n != 0 {
728 t.Errorf("ExtensionFieldTypes.Len() = %v, want 0", n)
729 }
Joe Tsai08e00302018-11-26 22:32:06 -0800730}
Joe Tsaif0c01e42018-11-06 13:05:20 -0800731
Joe Tsai08e00302018-11-26 22:32:06 -0800732func TestExtensionConvert(t *testing.T) {
733 for i := range extensionTypes {
734 i := i
735 t.Run("", func(t *testing.T) {
736 t.Parallel()
737
738 wantType := extensionTypes[i]
739 wantDesc := extensionDescs[i]
740 gotType := plegacy.Export{}.ExtensionTypeFromDesc(wantDesc)
741 gotDesc := plegacy.Export{}.ExtensionDescFromType(wantType)
742
743 // TODO: We need a test package to compare descriptors.
744 type list interface {
745 Len() int
746 pragma.DoNotImplement
747 }
748 opts := cmp.Options{
749 cmp.Comparer(func(x, y reflect.Type) bool {
750 return x == y
751 }),
752 cmp.Transformer("", func(x list) []interface{} {
753 out := make([]interface{}, x.Len())
754 v := reflect.ValueOf(x)
755 for i := 0; i < x.Len(); i++ {
756 m := v.MethodByName("Get")
757 out[i] = m.Call([]reflect.Value{reflect.ValueOf(i)})[0].Interface()
758 }
759 return out
760 }),
761 cmp.Transformer("", func(x pref.Descriptor) map[string]interface{} {
762 out := make(map[string]interface{})
763 v := reflect.ValueOf(x)
764 for i := 0; i < v.NumMethod(); i++ {
765 name := v.Type().Method(i).Name
766 if m := v.Method(i); m.Type().NumIn() == 0 && m.Type().NumOut() == 1 {
767 switch name {
768 case "New":
769 // Ignore New since it a constructor.
770 case "Options":
771 // Ignore descriptor options since protos are not cmperable.
772 case "EnumType", "MessageType", "ExtendedType":
773 // Avoid descending into a dependency to avoid a cycle.
774 // Just record the full name if available.
775 //
776 // TODO: Cycle support in cmp would be useful here.
777 v := m.Call(nil)[0]
778 if !v.IsNil() {
779 out[name] = v.Interface().(pref.Descriptor).FullName()
780 }
781 default:
782 out[name] = m.Call(nil)[0].Interface()
783 }
784 }
785 }
786 return out
787 }),
788 cmp.Transformer("", func(v pref.Value) interface{} {
789 return v.Interface()
790 }),
791 }
792 if diff := cmp.Diff(&wantType, &gotType, opts); diff != "" {
793 t.Errorf("ExtensionType mismatch (-want, +got):\n%v", diff)
794 }
795
796 opts = cmp.Options{
Joe Tsai4fddeba2019-03-20 18:29:32 -0700797 cmpopts.IgnoreFields(piface.ExtensionDescV1{}, "Type"),
Joe Tsai08e00302018-11-26 22:32:06 -0800798 }
799 if diff := cmp.Diff(wantDesc, gotDesc, opts); diff != "" {
800 t.Errorf("ExtensionDesc mismatch (-want, +got):\n%v", diff)
801 }
802 })
803 }
Joe Tsaif0c01e42018-11-06 13:05:20 -0800804}