blob: caa00434dd8e95ed2325cfe4f2e8d76cfecaee31 [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
5package impl
6
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 Tsai95b02902018-10-31 18:23:42 -070013 protoV1 "github.com/golang/protobuf/proto"
Joe Tsaie2afdc22018-10-25 14:06:56 -070014 "github.com/golang/protobuf/v2/internal/encoding/pack"
Joe Tsai90fe9962018-10-18 11:06:29 -070015 "github.com/golang/protobuf/v2/internal/pragma"
16 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
17 ptype "github.com/golang/protobuf/v2/reflect/prototype"
18 "github.com/google/go-cmp/cmp"
19)
20
21func mustLoadFileDesc(b []byte) pref.FileDescriptor {
22 fd, err := ptype.NewFileFromDescriptorProto(loadFileDesc(b), nil)
23 if err != nil {
24 panic(err)
25 }
26 return fd
27}
28
29var fileDescLP2 = mustLoadFileDesc(LP2FileDescriptor)
30var fileDescLP3 = mustLoadFileDesc(LP3FileDescriptor)
31
Joe Tsaie2afdc22018-10-25 14:06:56 -070032func TestLegacyDescriptor(t *testing.T) {
Joe Tsai90fe9962018-10-18 11:06:29 -070033 tests := []struct {
34 got pref.Descriptor
35 want pref.Descriptor
36 }{{
37 got: loadEnumDesc(reflect.TypeOf(LP2MapEnum(0))),
38 want: fileDescLP2.Enums().ByName("LP2MapEnum"),
39 }, {
40 got: loadEnumDesc(reflect.TypeOf(LP2SiblingEnum(0))),
41 want: fileDescLP2.Enums().ByName("LP2SiblingEnum"),
42 }, {
43 got: loadEnumDesc(reflect.TypeOf(LP2Message_LP2ChildEnum(0))),
44 want: fileDescLP2.Messages().ByName("LP2Message").Enums().ByName("LP2ChildEnum"),
45 }, {
46 got: loadMessageDesc(reflect.TypeOf(new(LP2Message))),
47 want: fileDescLP2.Messages().ByName("LP2Message"),
48 }, {
49 got: loadMessageDesc(reflect.TypeOf(new(LP2Message_LP2ChildMessage))),
50 want: fileDescLP2.Messages().ByName("LP2Message").Messages().ByName("LP2ChildMessage"),
51 }, {
52 got: loadMessageDesc(reflect.TypeOf(new(LP2Message_LP2NamedGroup))),
53 want: fileDescLP2.Messages().ByName("LP2Message").Messages().ByName("LP2NamedGroup"),
54 }, {
55 got: loadMessageDesc(reflect.TypeOf(new(LP2Message_OptionalGroup))),
56 want: fileDescLP2.Messages().ByName("LP2Message").Messages().ByName("OptionalGroup"),
57 }, {
58 got: loadMessageDesc(reflect.TypeOf(new(LP2Message_RequiredGroup))),
59 want: fileDescLP2.Messages().ByName("LP2Message").Messages().ByName("RequiredGroup"),
60 }, {
61 got: loadMessageDesc(reflect.TypeOf(new(LP2Message_RepeatedGroup))),
62 want: fileDescLP2.Messages().ByName("LP2Message").Messages().ByName("RepeatedGroup"),
63 }, {
64 got: loadMessageDesc(reflect.TypeOf(new(LP2SiblingMessage))),
65 want: fileDescLP2.Messages().ByName("LP2SiblingMessage"),
66 }, {
67 got: loadEnumDesc(reflect.TypeOf(LP3SiblingEnum(0))),
68 want: fileDescLP3.Enums().ByName("LP3SiblingEnum"),
69 }, {
70 got: loadEnumDesc(reflect.TypeOf(LP3Message_LP3ChildEnum(0))),
71 want: fileDescLP3.Messages().ByName("LP3Message").Enums().ByName("LP3ChildEnum"),
72 }, {
73 got: loadMessageDesc(reflect.TypeOf(new(LP3Message))),
74 want: fileDescLP3.Messages().ByName("LP3Message"),
75 }, {
76 got: loadMessageDesc(reflect.TypeOf(new(LP3Message_LP3ChildMessage))),
77 want: fileDescLP3.Messages().ByName("LP3Message").Messages().ByName("LP3ChildMessage"),
78 }, {
79 got: loadMessageDesc(reflect.TypeOf(new(LP3SiblingMessage))),
80 want: fileDescLP3.Messages().ByName("LP3SiblingMessage"),
81 }}
82
83 type list interface {
84 Len() int
85 pragma.DoNotImplement
86 }
87 opts := cmp.Options{
88 cmp.Transformer("", func(x list) []interface{} {
89 out := make([]interface{}, x.Len())
90 v := reflect.ValueOf(x)
91 for i := 0; i < x.Len(); i++ {
92 m := v.MethodByName("Get")
93 out[i] = m.Call([]reflect.Value{reflect.ValueOf(i)})[0].Interface()
94 }
95 return out
96 }),
97 cmp.Transformer("", func(x pref.Descriptor) map[string]interface{} {
98 out := make(map[string]interface{})
99 v := reflect.ValueOf(x)
100 for i := 0; i < v.NumMethod(); i++ {
101 name := v.Type().Method(i).Name
102 if m := v.Method(i); m.Type().NumIn() == 0 && m.Type().NumOut() == 1 {
103 switch name {
104 case "Index":
105 // Ignore index since legacy descriptors have no parent.
Damien Neil204f1c02018-10-23 15:03:38 -0700106 case "Options":
107 // Ignore descriptor options since protos are not cmperable.
Joe Tsai90fe9962018-10-18 11:06:29 -0700108 case "Messages", "Enums":
109 // Ignore nested message and enum declarations since
110 // legacy descriptors are all created standalone.
111 case "OneofType", "ExtendedType", "MessageType", "EnumType":
112 // Avoid descending into a dependency to avoid a cycle.
113 // Just record the full name if available.
114 //
115 // TODO: Cycle support in cmp would be useful here.
116 v := m.Call(nil)[0]
117 if !v.IsNil() {
118 out[name] = v.Interface().(pref.Descriptor).FullName()
119 }
120 default:
121 out[name] = m.Call(nil)[0].Interface()
122 }
123 }
124 }
125 return out
126 }),
127 cmp.Transformer("", func(v pref.Value) interface{} {
128 return v.Interface()
129 }),
130 }
131
132 for _, tt := range tests {
133 t.Run(string(tt.want.FullName()), func(t *testing.T) {
134 if diff := cmp.Diff(&tt.want, &tt.got, opts); diff != "" {
135 t.Errorf("descriptor mismatch (-want, +got):\n%s", diff)
136 }
137 })
138 }
139}
Joe Tsaie2afdc22018-10-25 14:06:56 -0700140
Joe Tsai95b02902018-10-31 18:23:42 -0700141type legacyUnknownMessage struct {
142 XXX_unrecognized []byte
143 protoV1.XXX_InternalExtensions
144}
145
146func (*legacyUnknownMessage) ExtensionRangeArray() []protoV1.ExtensionRange {
147 return []protoV1.ExtensionRange{{Start: 10, End: 20}, {Start: 40, End: 80}}
148}
149
Joe Tsaie2afdc22018-10-25 14:06:56 -0700150func TestLegacyUnknown(t *testing.T) {
151 rawOf := func(toks ...pack.Token) pref.RawFields {
152 return pref.RawFields(pack.Message(toks).Marshal())
153 }
154 raw1a := rawOf(pack.Tag{1, pack.VarintType}, pack.Svarint(-4321)) // 08c143
155 raw1b := rawOf(pack.Tag{1, pack.Fixed32Type}, pack.Uint32(0xdeadbeef)) // 0defbeadde
156 raw1c := rawOf(pack.Tag{1, pack.Fixed64Type}, pack.Float64(math.Pi)) // 09182d4454fb210940
157 raw2a := rawOf(pack.Tag{2, pack.BytesType}, pack.String("hello, world!")) // 120d68656c6c6f2c20776f726c6421
158 raw2b := rawOf(pack.Tag{2, pack.VarintType}, pack.Uvarint(1234)) // 10d209
159 raw3a := rawOf(pack.Tag{3, pack.StartGroupType}, pack.Tag{3, pack.EndGroupType}) // 1b1c
160 raw3b := rawOf(pack.Tag{3, pack.BytesType}, pack.Bytes("\xde\xad\xbe\xef")) // 1a04deadbeef
161
Joe Tsai95b02902018-10-31 18:23:42 -0700162 raw1 := rawOf(pack.Tag{1, pack.BytesType}, pack.Bytes("1")) // 0a0131
163 raw3 := rawOf(pack.Tag{3, pack.BytesType}, pack.Bytes("3")) // 1a0133
164 raw10 := rawOf(pack.Tag{10, pack.BytesType}, pack.Bytes("10")) // 52023130 - extension
165 raw15 := rawOf(pack.Tag{15, pack.BytesType}, pack.Bytes("15")) // 7a023135 - extension
166 raw26 := rawOf(pack.Tag{26, pack.BytesType}, pack.Bytes("26")) // d201023236
167 raw32 := rawOf(pack.Tag{32, pack.BytesType}, pack.Bytes("32")) // 8202023332
168 raw45 := rawOf(pack.Tag{45, pack.BytesType}, pack.Bytes("45")) // ea02023435 - extension
169 raw46 := rawOf(pack.Tag{45, pack.BytesType}, pack.Bytes("46")) // ea02023436 - extension
170 raw47 := rawOf(pack.Tag{45, pack.BytesType}, pack.Bytes("47")) // ea02023437 - extension
171 raw99 := rawOf(pack.Tag{99, pack.BytesType}, pack.Bytes("99")) // 9a06023939
172
Joe Tsaie2afdc22018-10-25 14:06:56 -0700173 joinRaw := func(bs ...pref.RawFields) (out []byte) {
174 for _, b := range bs {
175 out = append(out, b...)
176 }
177 return out
178 }
179
Joe Tsai95b02902018-10-31 18:23:42 -0700180 m := new(legacyUnknownMessage)
181 fs := new(MessageType).MessageOf(m).UnknownFields()
182
Joe Tsaie2afdc22018-10-25 14:06:56 -0700183 if got, want := fs.Len(), 0; got != want {
184 t.Errorf("Len() = %d, want %d", got, want)
185 }
Joe Tsai95b02902018-10-31 18:23:42 -0700186 if got, want := m.XXX_unrecognized, joinRaw(); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -0700187 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
188 }
189
190 fs.Set(1, raw1a)
191 fs.Set(1, append(fs.Get(1), raw1b...))
192 fs.Set(1, append(fs.Get(1), raw1c...))
193 if got, want := fs.Len(), 1; got != want {
194 t.Errorf("Len() = %d, want %d", got, want)
195 }
Joe Tsai95b02902018-10-31 18:23:42 -0700196 if got, want := m.XXX_unrecognized, joinRaw(raw1a, raw1b, raw1c); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -0700197 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
198 }
199
200 fs.Set(2, raw2a)
201 if got, want := fs.Len(), 2; got != want {
202 t.Errorf("Len() = %d, want %d", got, want)
203 }
Joe Tsai95b02902018-10-31 18:23:42 -0700204 if got, want := m.XXX_unrecognized, joinRaw(raw1a, raw1b, raw1c, raw2a); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -0700205 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
206 }
207
208 if got, want := fs.Get(1), joinRaw(raw1a, raw1b, raw1c); !bytes.Equal(got, want) {
209 t.Errorf("Get(%d) = %x, want %x", 1, got, want)
210 }
211 if got, want := fs.Get(2), joinRaw(raw2a); !bytes.Equal(got, want) {
212 t.Errorf("Get(%d) = %x, want %x", 2, got, want)
213 }
214 if got, want := fs.Get(3), joinRaw(); !bytes.Equal(got, want) {
215 t.Errorf("Get(%d) = %x, want %x", 3, got, want)
216 }
217
218 fs.Set(1, nil) // remove field 1
219 if got, want := fs.Len(), 1; got != want {
220 t.Errorf("Len() = %d, want %d", got, want)
221 }
Joe Tsai95b02902018-10-31 18:23:42 -0700222 if got, want := m.XXX_unrecognized, joinRaw(raw2a); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -0700223 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
224 }
225
226 // Simulate manual appending of raw field data.
Joe Tsai95b02902018-10-31 18:23:42 -0700227 m.XXX_unrecognized = append(m.XXX_unrecognized, joinRaw(raw3a, raw1a, raw1b, raw2b, raw3b, raw1c)...)
Joe Tsaie2afdc22018-10-25 14:06:56 -0700228 if got, want := fs.Len(), 3; got != want {
229 t.Errorf("Len() = %d, want %d", got, want)
230 }
231
232 // Verify range iteration order.
233 var i int
234 want := []struct {
235 num pref.FieldNumber
236 raw pref.RawFields
237 }{
Joe Tsaie2afdc22018-10-25 14:06:56 -0700238 {2, joinRaw(raw2a, raw2b)},
Joe Tsai2d5a1692018-10-29 02:10:42 -0700239 {3, joinRaw(raw3a, raw3b)},
Joe Tsaie2afdc22018-10-25 14:06:56 -0700240 {1, joinRaw(raw1a, raw1b, raw1c)},
241 }
242 fs.Range(func(num pref.FieldNumber, raw pref.RawFields) bool {
243 if i < len(want) {
244 if num != want[i].num || !bytes.Equal(raw, want[i].raw) {
245 t.Errorf("Range(%d) = (%d, %x), want (%d, %x)", i, num, raw, want[i].num, want[i].raw)
246 }
247 } else {
248 t.Errorf("unexpected Range iteration: %d", i)
249 }
250 i++
251 return true
252 })
253
254 fs.Set(2, fs.Get(2)) // moves field 2 to the end
255 if got, want := fs.Len(), 3; got != want {
256 t.Errorf("Len() = %d, want %d", got, want)
257 }
Joe Tsai95b02902018-10-31 18:23:42 -0700258 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 -0700259 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
260 }
261 fs.Set(1, nil) // remove field 1
262 if got, want := fs.Len(), 2; got != want {
263 t.Errorf("Len() = %d, want %d", got, want)
264 }
Joe Tsai95b02902018-10-31 18:23:42 -0700265 if got, want := m.XXX_unrecognized, joinRaw(raw3a, raw3b, raw2a, raw2b); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -0700266 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
267 }
268
269 // Remove all fields.
270 fs.Range(func(n pref.FieldNumber, b pref.RawFields) bool {
271 fs.Set(n, nil)
272 return true
273 })
274 if got, want := fs.Len(), 0; got != want {
275 t.Errorf("Len() = %d, want %d", got, want)
276 }
Joe Tsai95b02902018-10-31 18:23:42 -0700277 if got, want := m.XXX_unrecognized, joinRaw(); !bytes.Equal(got, want) {
Joe Tsaie2afdc22018-10-25 14:06:56 -0700278 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
279 }
Joe Tsai95b02902018-10-31 18:23:42 -0700280
281 fs.Set(1, raw1)
282 if got, want := fs.Len(), 1; got != want {
283 t.Errorf("Len() = %d, want %d", got, want)
284 }
285 if got, want := m.XXX_unrecognized, joinRaw(raw1); !bytes.Equal(got, want) {
286 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
287 }
288
289 fs.Set(45, raw45)
290 fs.Set(10, raw10) // extension
291 fs.Set(32, raw32)
292 fs.Set(1, nil) // deletion
293 fs.Set(26, raw26)
294 fs.Set(47, raw47) // extension
295 fs.Set(46, raw46) // extension
296 if got, want := fs.Len(), 6; got != want {
297 t.Errorf("Len() = %d, want %d", got, want)
298 }
299 if got, want := m.XXX_unrecognized, joinRaw(raw32, raw26); !bytes.Equal(got, want) {
300 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
301 }
302
303 // Verify iteration order.
304 i = 0
305 want = []struct {
306 num pref.FieldNumber
307 raw pref.RawFields
308 }{
309 {32, raw32},
310 {26, raw26},
311 {10, raw10}, // extension
312 {45, raw45}, // extension
313 {46, raw46}, // extension
314 {47, raw47}, // extension
315 }
316 fs.Range(func(num pref.FieldNumber, raw pref.RawFields) bool {
317 if i < len(want) {
318 if num != want[i].num || !bytes.Equal(raw, want[i].raw) {
319 t.Errorf("Range(%d) = (%d, %x), want (%d, %x)", i, num, raw, want[i].num, want[i].raw)
320 }
321 } else {
322 t.Errorf("unexpected Range iteration: %d", i)
323 }
324 i++
325 return true
326 })
327
328 // Perform partial deletion while iterating.
329 i = 0
330 fs.Range(func(num pref.FieldNumber, raw pref.RawFields) bool {
331 if i%2 == 0 {
332 fs.Set(num, nil)
333 }
334 i++
335 return true
336 })
337
338 if got, want := fs.Len(), 3; got != want {
339 t.Errorf("Len() = %d, want %d", got, want)
340 }
341 if got, want := m.XXX_unrecognized, joinRaw(raw26); !bytes.Equal(got, want) {
342 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
343 }
344
345 fs.Set(15, raw15) // extension
346 fs.Set(3, raw3)
347 fs.Set(99, raw99)
348 if got, want := fs.Len(), 6; got != want {
349 t.Errorf("Len() = %d, want %d", got, want)
350 }
351 if got, want := m.XXX_unrecognized, joinRaw(raw26, raw3, raw99); !bytes.Equal(got, want) {
352 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
353 }
354
355 // Perform partial iteration.
356 i = 0
357 want = []struct {
358 num pref.FieldNumber
359 raw pref.RawFields
360 }{
361 {26, raw26},
362 {3, raw3},
363 }
364 fs.Range(func(num pref.FieldNumber, raw pref.RawFields) bool {
365 if i < len(want) {
366 if num != want[i].num || !bytes.Equal(raw, want[i].raw) {
367 t.Errorf("Range(%d) = (%d, %x), want (%d, %x)", i, num, raw, want[i].num, want[i].raw)
368 }
369 } else {
370 t.Errorf("unexpected Range iteration: %d", i)
371 }
372 i++
373 return i < 2
374 })
Joe Tsaie2afdc22018-10-25 14:06:56 -0700375}