blob: 32253f39677e62b5776b554526a870574e08b402 [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 Tsaie2afdc22018-10-25 14:06:56 -070013 "github.com/golang/protobuf/v2/internal/encoding/pack"
Joe Tsai90fe9962018-10-18 11:06:29 -070014 "github.com/golang/protobuf/v2/internal/pragma"
15 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
16 ptype "github.com/golang/protobuf/v2/reflect/prototype"
17 "github.com/google/go-cmp/cmp"
18)
19
20func mustLoadFileDesc(b []byte) pref.FileDescriptor {
21 fd, err := ptype.NewFileFromDescriptorProto(loadFileDesc(b), nil)
22 if err != nil {
23 panic(err)
24 }
25 return fd
26}
27
28var fileDescLP2 = mustLoadFileDesc(LP2FileDescriptor)
29var fileDescLP3 = mustLoadFileDesc(LP3FileDescriptor)
30
Joe Tsaie2afdc22018-10-25 14:06:56 -070031func TestLegacyDescriptor(t *testing.T) {
Joe Tsai90fe9962018-10-18 11:06:29 -070032 tests := []struct {
33 got pref.Descriptor
34 want pref.Descriptor
35 }{{
36 got: loadEnumDesc(reflect.TypeOf(LP2MapEnum(0))),
37 want: fileDescLP2.Enums().ByName("LP2MapEnum"),
38 }, {
39 got: loadEnumDesc(reflect.TypeOf(LP2SiblingEnum(0))),
40 want: fileDescLP2.Enums().ByName("LP2SiblingEnum"),
41 }, {
42 got: loadEnumDesc(reflect.TypeOf(LP2Message_LP2ChildEnum(0))),
43 want: fileDescLP2.Messages().ByName("LP2Message").Enums().ByName("LP2ChildEnum"),
44 }, {
45 got: loadMessageDesc(reflect.TypeOf(new(LP2Message))),
46 want: fileDescLP2.Messages().ByName("LP2Message"),
47 }, {
48 got: loadMessageDesc(reflect.TypeOf(new(LP2Message_LP2ChildMessage))),
49 want: fileDescLP2.Messages().ByName("LP2Message").Messages().ByName("LP2ChildMessage"),
50 }, {
51 got: loadMessageDesc(reflect.TypeOf(new(LP2Message_LP2NamedGroup))),
52 want: fileDescLP2.Messages().ByName("LP2Message").Messages().ByName("LP2NamedGroup"),
53 }, {
54 got: loadMessageDesc(reflect.TypeOf(new(LP2Message_OptionalGroup))),
55 want: fileDescLP2.Messages().ByName("LP2Message").Messages().ByName("OptionalGroup"),
56 }, {
57 got: loadMessageDesc(reflect.TypeOf(new(LP2Message_RequiredGroup))),
58 want: fileDescLP2.Messages().ByName("LP2Message").Messages().ByName("RequiredGroup"),
59 }, {
60 got: loadMessageDesc(reflect.TypeOf(new(LP2Message_RepeatedGroup))),
61 want: fileDescLP2.Messages().ByName("LP2Message").Messages().ByName("RepeatedGroup"),
62 }, {
63 got: loadMessageDesc(reflect.TypeOf(new(LP2SiblingMessage))),
64 want: fileDescLP2.Messages().ByName("LP2SiblingMessage"),
65 }, {
66 got: loadEnumDesc(reflect.TypeOf(LP3SiblingEnum(0))),
67 want: fileDescLP3.Enums().ByName("LP3SiblingEnum"),
68 }, {
69 got: loadEnumDesc(reflect.TypeOf(LP3Message_LP3ChildEnum(0))),
70 want: fileDescLP3.Messages().ByName("LP3Message").Enums().ByName("LP3ChildEnum"),
71 }, {
72 got: loadMessageDesc(reflect.TypeOf(new(LP3Message))),
73 want: fileDescLP3.Messages().ByName("LP3Message"),
74 }, {
75 got: loadMessageDesc(reflect.TypeOf(new(LP3Message_LP3ChildMessage))),
76 want: fileDescLP3.Messages().ByName("LP3Message").Messages().ByName("LP3ChildMessage"),
77 }, {
78 got: loadMessageDesc(reflect.TypeOf(new(LP3SiblingMessage))),
79 want: fileDescLP3.Messages().ByName("LP3SiblingMessage"),
80 }}
81
82 type list interface {
83 Len() int
84 pragma.DoNotImplement
85 }
86 opts := cmp.Options{
87 cmp.Transformer("", func(x list) []interface{} {
88 out := make([]interface{}, x.Len())
89 v := reflect.ValueOf(x)
90 for i := 0; i < x.Len(); i++ {
91 m := v.MethodByName("Get")
92 out[i] = m.Call([]reflect.Value{reflect.ValueOf(i)})[0].Interface()
93 }
94 return out
95 }),
96 cmp.Transformer("", func(x pref.Descriptor) map[string]interface{} {
97 out := make(map[string]interface{})
98 v := reflect.ValueOf(x)
99 for i := 0; i < v.NumMethod(); i++ {
100 name := v.Type().Method(i).Name
101 if m := v.Method(i); m.Type().NumIn() == 0 && m.Type().NumOut() == 1 {
102 switch name {
103 case "Index":
104 // Ignore index since legacy descriptors have no parent.
Damien Neil204f1c02018-10-23 15:03:38 -0700105 case "Options":
106 // Ignore descriptor options since protos are not cmperable.
Joe Tsai90fe9962018-10-18 11:06:29 -0700107 case "Messages", "Enums":
108 // Ignore nested message and enum declarations since
109 // legacy descriptors are all created standalone.
110 case "OneofType", "ExtendedType", "MessageType", "EnumType":
111 // Avoid descending into a dependency to avoid a cycle.
112 // Just record the full name if available.
113 //
114 // TODO: Cycle support in cmp would be useful here.
115 v := m.Call(nil)[0]
116 if !v.IsNil() {
117 out[name] = v.Interface().(pref.Descriptor).FullName()
118 }
119 default:
120 out[name] = m.Call(nil)[0].Interface()
121 }
122 }
123 }
124 return out
125 }),
126 cmp.Transformer("", func(v pref.Value) interface{} {
127 return v.Interface()
128 }),
129 }
130
131 for _, tt := range tests {
132 t.Run(string(tt.want.FullName()), func(t *testing.T) {
133 if diff := cmp.Diff(&tt.want, &tt.got, opts); diff != "" {
134 t.Errorf("descriptor mismatch (-want, +got):\n%s", diff)
135 }
136 })
137 }
138}
Joe Tsaie2afdc22018-10-25 14:06:56 -0700139
140func TestLegacyUnknown(t *testing.T) {
141 rawOf := func(toks ...pack.Token) pref.RawFields {
142 return pref.RawFields(pack.Message(toks).Marshal())
143 }
144 raw1a := rawOf(pack.Tag{1, pack.VarintType}, pack.Svarint(-4321)) // 08c143
145 raw1b := rawOf(pack.Tag{1, pack.Fixed32Type}, pack.Uint32(0xdeadbeef)) // 0defbeadde
146 raw1c := rawOf(pack.Tag{1, pack.Fixed64Type}, pack.Float64(math.Pi)) // 09182d4454fb210940
147 raw2a := rawOf(pack.Tag{2, pack.BytesType}, pack.String("hello, world!")) // 120d68656c6c6f2c20776f726c6421
148 raw2b := rawOf(pack.Tag{2, pack.VarintType}, pack.Uvarint(1234)) // 10d209
149 raw3a := rawOf(pack.Tag{3, pack.StartGroupType}, pack.Tag{3, pack.EndGroupType}) // 1b1c
150 raw3b := rawOf(pack.Tag{3, pack.BytesType}, pack.Bytes("\xde\xad\xbe\xef")) // 1a04deadbeef
151
152 joinRaw := func(bs ...pref.RawFields) (out []byte) {
153 for _, b := range bs {
154 out = append(out, b...)
155 }
156 return out
157 }
158
159 var fs legacyUnknownBytes
160 if got, want := fs.Len(), 0; got != want {
161 t.Errorf("Len() = %d, want %d", got, want)
162 }
163 if got, want := []byte(fs), joinRaw(); !bytes.Equal(got, want) {
164 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
165 }
166
167 fs.Set(1, raw1a)
168 fs.Set(1, append(fs.Get(1), raw1b...))
169 fs.Set(1, append(fs.Get(1), raw1c...))
170 if got, want := fs.Len(), 1; got != want {
171 t.Errorf("Len() = %d, want %d", got, want)
172 }
173 if got, want := []byte(fs), joinRaw(raw1a, raw1b, raw1c); !bytes.Equal(got, want) {
174 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
175 }
176
177 fs.Set(2, raw2a)
178 if got, want := fs.Len(), 2; got != want {
179 t.Errorf("Len() = %d, want %d", got, want)
180 }
181 if got, want := []byte(fs), joinRaw(raw1a, raw1b, raw1c, raw2a); !bytes.Equal(got, want) {
182 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
183 }
184
185 if got, want := fs.Get(1), joinRaw(raw1a, raw1b, raw1c); !bytes.Equal(got, want) {
186 t.Errorf("Get(%d) = %x, want %x", 1, got, want)
187 }
188 if got, want := fs.Get(2), joinRaw(raw2a); !bytes.Equal(got, want) {
189 t.Errorf("Get(%d) = %x, want %x", 2, got, want)
190 }
191 if got, want := fs.Get(3), joinRaw(); !bytes.Equal(got, want) {
192 t.Errorf("Get(%d) = %x, want %x", 3, got, want)
193 }
194
195 fs.Set(1, nil) // remove field 1
196 if got, want := fs.Len(), 1; got != want {
197 t.Errorf("Len() = %d, want %d", got, want)
198 }
199 if got, want := []byte(fs), joinRaw(raw2a); !bytes.Equal(got, want) {
200 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
201 }
202
203 // Simulate manual appending of raw field data.
204 fs = append(fs, joinRaw(raw3a, raw1a, raw1b, raw3b, raw2b, raw1c)...)
205 if got, want := fs.Len(), 3; got != want {
206 t.Errorf("Len() = %d, want %d", got, want)
207 }
208
209 // Verify range iteration order.
210 var i int
211 want := []struct {
212 num pref.FieldNumber
213 raw pref.RawFields
214 }{
215 {3, joinRaw(raw3a, raw3b)},
216 {2, joinRaw(raw2a, raw2b)},
217 {1, joinRaw(raw1a, raw1b, raw1c)},
218 }
219 fs.Range(func(num pref.FieldNumber, raw pref.RawFields) bool {
220 if i < len(want) {
221 if num != want[i].num || !bytes.Equal(raw, want[i].raw) {
222 t.Errorf("Range(%d) = (%d, %x), want (%d, %x)", i, num, raw, want[i].num, want[i].raw)
223 }
224 } else {
225 t.Errorf("unexpected Range iteration: %d", i)
226 }
227 i++
228 return true
229 })
230
231 fs.Set(2, fs.Get(2)) // moves field 2 to the end
232 if got, want := fs.Len(), 3; got != want {
233 t.Errorf("Len() = %d, want %d", got, want)
234 }
235 if got, want := []byte(fs), joinRaw(raw3a, raw1a, raw1b, raw3b, raw1c, raw2a, raw2b); !bytes.Equal(got, want) {
236 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
237 }
238 fs.Set(1, nil) // remove field 1
239 if got, want := fs.Len(), 2; got != want {
240 t.Errorf("Len() = %d, want %d", got, want)
241 }
242 if got, want := []byte(fs), joinRaw(raw3a, raw3b, raw2a, raw2b); !bytes.Equal(got, want) {
243 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
244 }
245
246 // Remove all fields.
247 fs.Range(func(n pref.FieldNumber, b pref.RawFields) bool {
248 fs.Set(n, nil)
249 return true
250 })
251 if got, want := fs.Len(), 0; got != want {
252 t.Errorf("Len() = %d, want %d", got, want)
253 }
254 if got, want := []byte(fs), joinRaw(); !bytes.Equal(got, want) {
255 t.Errorf("data mismatch:\ngot: %x\nwant: %x", got, want)
256 }
257}