1
2
3
4
5 package protopack
6
7 import (
8 "bytes"
9 "encoding/hex"
10 "fmt"
11 "math"
12 "testing"
13
14 "github.com/google/go-cmp/cmp"
15
16 "google.golang.org/protobuf/encoding/prototext"
17 "google.golang.org/protobuf/reflect/protodesc"
18 "google.golang.org/protobuf/reflect/protoreflect"
19
20 "google.golang.org/protobuf/types/descriptorpb"
21 )
22
23 var msgDesc = func() protoreflect.MessageDescriptor {
24 const s = `
25 name: "test.proto"
26 syntax: "proto2"
27 message_type: [{
28 name: "Message"
29 field: [
30 {name:"f1" number:1 label:LABEL_REPEATED type:TYPE_BOOL options:{packed:true}},
31 {name:"f2" number:2 label:LABEL_REPEATED type:TYPE_INT64 options:{packed:true}},
32 {name:"f3" number:3 label:LABEL_REPEATED type:TYPE_SINT64 options:{packed:true}},
33 {name:"f4" number:4 label:LABEL_REPEATED type:TYPE_UINT64 options:{packed:true}},
34 {name:"f5" number:5 label:LABEL_REPEATED type:TYPE_FIXED32 options:{packed:true}},
35 {name:"f6" number:6 label:LABEL_REPEATED type:TYPE_SFIXED32 options:{packed:true}},
36 {name:"f7" number:7 label:LABEL_REPEATED type:TYPE_FLOAT options:{packed:true}},
37 {name:"f8" number:8 label:LABEL_REPEATED type:TYPE_FIXED64 options:{packed:true}},
38 {name:"f9" number:9 label:LABEL_REPEATED type:TYPE_SFIXED64 options:{packed:true}},
39 {name:"f10" number:10 label:LABEL_REPEATED type:TYPE_DOUBLE options:{packed:true}},
40 {name:"f11" number:11 label:LABEL_OPTIONAL type:TYPE_STRING},
41 {name:"f12" number:12 label:LABEL_OPTIONAL type:TYPE_BYTES},
42 {name:"f13" number:13 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".Message"},
43 {name:"f14" number:14 label:LABEL_OPTIONAL type:TYPE_GROUP type_name:".Message.F14"}
44 ]
45 nested_type: [{name: "F14"}]
46 }]
47 `
48 pb := new(descriptorpb.FileDescriptorProto)
49 if err := prototext.Unmarshal([]byte(s), pb); err != nil {
50 panic(err)
51 }
52 fd, err := protodesc.NewFile(pb, nil)
53 if err != nil {
54 panic(err)
55 }
56 return fd.Messages().Get(0)
57 }()
58
59
60 func dhex(s string) []byte {
61 b, err := hex.DecodeString(s)
62 if err != nil {
63 panic(err)
64 }
65 return b
66 }
67
68 func TestPack(t *testing.T) {
69 tests := []struct {
70 raw []byte
71 msg Message
72 msgDesc protoreflect.MessageDescriptor
73 inferMsg bool
74
75 wantOutCompact string
76 wantOutMulti string
77 wantOutSource string
78 }{{
79 raw: dhex("080088808080800002088280808080000a09010002828080808000"),
80 msg: Message{
81 Tag{1, VarintType}, Bool(false),
82 Denormalized{5, Tag{1, VarintType}}, Uvarint(2),
83 Tag{1, VarintType}, Denormalized{5, Uvarint(2)},
84 Tag{1, BytesType}, LengthPrefix{Bool(true), Bool(false), Uvarint(2), Denormalized{5, Uvarint(2)}},
85 },
86 msgDesc: msgDesc,
87 wantOutSource: `protopack.Message{
88 protopack.Tag{1, protopack.VarintType}, protopack.Bool(false),
89 protopack.Denormalized{+5, protopack.Tag{1, protopack.VarintType}}, protopack.Uvarint(2),
90 protopack.Tag{1, protopack.VarintType}, protopack.Denormalized{+5, protopack.Uvarint(2)},
91 protopack.Tag{1, protopack.BytesType}, protopack.LengthPrefix{protopack.Bool(true), protopack.Bool(false), protopack.Uvarint(2), protopack.Denormalized{+5, protopack.Uvarint(2)}},
92 }`,
93 }, {
94 raw: dhex("080088808080800002088280808080000a09010002828080808000"),
95 msg: Message{
96 Tag{1, VarintType}, Uvarint(0),
97 Denormalized{5, Tag{1, VarintType}}, Uvarint(2),
98 Tag{1, VarintType}, Denormalized{5, Uvarint(2)},
99 Tag{1, BytesType}, Bytes(Message{Bool(true), Bool(false), Uvarint(2), Denormalized{5, Uvarint(2)}}.Marshal()),
100 },
101 inferMsg: true,
102 }, {
103 raw: dhex("100010828080808000121980808080808080808001ffffffffffffffff7f828080808000"),
104 msg: Message{
105 Tag{2, VarintType}, Varint(0),
106 Tag{2, VarintType}, Denormalized{5, Varint(2)},
107 Tag{2, BytesType}, LengthPrefix{Varint(math.MinInt64), Varint(math.MaxInt64), Denormalized{5, Varint(2)}},
108 },
109 msgDesc: msgDesc,
110 wantOutCompact: `Message{Tag{2, Varint}, Varint(0), Tag{2, Varint}, Denormalized{+5, Varint(2)}, Tag{2, Bytes}, LengthPrefix{Varint(-9223372036854775808), Varint(9223372036854775807), Denormalized{+5, Varint(2)}}}`,
111 }, {
112 raw: dhex("1801188180808080001a1affffffffffffffffff01feffffffffffffffff01818080808000"),
113 msg: Message{
114 Tag{3, VarintType}, Svarint(-1),
115 Tag{3, VarintType}, Denormalized{5, Svarint(-1)},
116 Tag{3, BytesType}, LengthPrefix{Svarint(math.MinInt64), Svarint(math.MaxInt64), Denormalized{5, Svarint(-1)}},
117 },
118 msgDesc: msgDesc,
119 wantOutMulti: `Message{
120 Tag{3, Varint}, Svarint(-1),
121 Tag{3, Varint}, Denormalized{+5, Svarint(-1)},
122 Tag{3, Bytes}, LengthPrefix{Svarint(-9223372036854775808), Svarint(9223372036854775807), Denormalized{+5, Svarint(-1)}},
123 }`,
124 }, {
125 raw: dhex("200120818080808000221100ffffffffffffffffff01818080808000"),
126 msg: Message{
127 Tag{4, VarintType}, Uvarint(+1),
128 Tag{4, VarintType}, Denormalized{5, Uvarint(+1)},
129 Tag{4, BytesType}, LengthPrefix{Uvarint(0), Uvarint(math.MaxUint64), Denormalized{5, Uvarint(+1)}},
130 },
131 msgDesc: msgDesc,
132 wantOutSource: `protopack.Message{
133 protopack.Tag{4, protopack.VarintType}, protopack.Uvarint(1),
134 protopack.Tag{4, protopack.VarintType}, protopack.Denormalized{+5, protopack.Uvarint(1)},
135 protopack.Tag{4, protopack.BytesType}, protopack.LengthPrefix{protopack.Uvarint(0), protopack.Uvarint(18446744073709551615), protopack.Denormalized{+5, protopack.Uvarint(1)}},
136 }`,
137 }, {
138 raw: dhex("2d010000002a0800000000ffffffff"),
139 msg: Message{
140 Tag{5, Fixed32Type}, Uint32(+1),
141 Tag{5, BytesType}, LengthPrefix{Uint32(0), Uint32(math.MaxUint32)},
142 },
143 msgDesc: msgDesc,
144 wantOutCompact: `Message{Tag{5, Fixed32}, Uint32(1), Tag{5, Bytes}, LengthPrefix{Uint32(0), Uint32(4294967295)}}`,
145 }, {
146 raw: dhex("35ffffffff320800000080ffffff7f"),
147 msg: Message{
148 Tag{6, Fixed32Type}, Int32(-1),
149 Tag{6, BytesType}, LengthPrefix{Int32(math.MinInt32), Int32(math.MaxInt32)},
150 },
151 msgDesc: msgDesc,
152 wantOutMulti: `Message{
153 Tag{6, Fixed32}, Int32(-1),
154 Tag{6, Bytes}, LengthPrefix{Int32(-2147483648), Int32(2147483647)},
155 }`,
156 }, {
157 raw: dhex("3ddb0f49403a1001000000ffff7f7f0000807f000080ff"),
158 msg: Message{
159 Tag{7, Fixed32Type}, Float32(math.Pi),
160 Tag{7, BytesType}, LengthPrefix{Float32(math.SmallestNonzeroFloat32), Float32(math.MaxFloat32), Float32(math.Inf(+1)), Float32(math.Inf(-1))},
161 },
162 msgDesc: msgDesc,
163 wantOutSource: `protopack.Message{
164 protopack.Tag{7, protopack.Fixed32Type}, protopack.Float32(3.1415927),
165 protopack.Tag{7, protopack.BytesType}, protopack.LengthPrefix{protopack.Float32(1e-45), protopack.Float32(3.4028235e+38), protopack.Float32(math.Inf(+1)), protopack.Float32(math.Inf(-1))},
166 }`,
167 }, {
168 raw: dhex("41010000000000000042100000000000000000ffffffffffffffff"),
169 msg: Message{
170 Tag{8, Fixed64Type}, Uint64(+1),
171 Tag{8, BytesType}, LengthPrefix{Uint64(0), Uint64(math.MaxUint64)},
172 },
173 msgDesc: msgDesc,
174 wantOutCompact: `Message{Tag{8, Fixed64}, Uint64(1), Tag{8, Bytes}, LengthPrefix{Uint64(0), Uint64(18446744073709551615)}}`,
175 }, {
176 raw: dhex("49ffffffffffffffff4a100000000000000080ffffffffffffff7f"),
177 msg: Message{
178 Tag{9, Fixed64Type}, Int64(-1),
179 Tag{9, BytesType}, LengthPrefix{Int64(math.MinInt64), Int64(math.MaxInt64)},
180 },
181 msgDesc: msgDesc,
182 wantOutMulti: `Message{
183 Tag{9, Fixed64}, Int64(-1),
184 Tag{9, Bytes}, LengthPrefix{Int64(-9223372036854775808), Int64(9223372036854775807)},
185 }`,
186 }, {
187 raw: dhex("51182d4454fb21094052200100000000000000ffffffffffffef7f000000000000f07f000000000000f0ff"),
188 msg: Message{
189 Tag{10, Fixed64Type}, Float64(math.Pi),
190 Tag{10, BytesType}, LengthPrefix{Float64(math.SmallestNonzeroFloat64), Float64(math.MaxFloat64), Float64(math.Inf(+1)), Float64(math.Inf(-1))},
191 },
192 msgDesc: msgDesc,
193 wantOutMulti: `Message{
194 Tag{10, Fixed64}, Float64(3.141592653589793),
195 Tag{10, Bytes}, LengthPrefix{Float64(5e-324), Float64(1.7976931348623157e+308), Float64(+Inf), Float64(-Inf)},
196 }`,
197 }, {
198 raw: dhex("5a06737472696e675a868080808000737472696e67"),
199 msg: Message{
200 Tag{11, BytesType}, String("string"),
201 Tag{11, BytesType}, Denormalized{+5, String("string")},
202 },
203 msgDesc: msgDesc,
204 wantOutCompact: `Message{Tag{11, Bytes}, String("string"), Tag{11, Bytes}, Denormalized{+5, String("string")}}`,
205 }, {
206 raw: dhex("62056279746573628580808080006279746573"),
207 msg: Message{
208 Tag{12, BytesType}, Bytes("bytes"),
209 Tag{12, BytesType}, Denormalized{+5, Bytes("bytes")},
210 },
211 msgDesc: msgDesc,
212 wantOutMulti: `Message{
213 Tag{12, Bytes}, Bytes("bytes"),
214 Tag{12, Bytes}, Denormalized{+5, Bytes("bytes")},
215 }`,
216 }, {
217 raw: dhex("6a28a006ffffffffffffffffff01a506ffffffffa106ffffffffffffffffa206056279746573a306a406"),
218 msg: Message{
219 Tag{13, BytesType}, LengthPrefix(Message{
220 Tag{100, VarintType}, Uvarint(math.MaxUint64),
221 Tag{100, Fixed32Type}, Uint32(math.MaxUint32),
222 Tag{100, Fixed64Type}, Uint64(math.MaxUint64),
223 Tag{100, BytesType}, Bytes("bytes"),
224 Tag{100, StartGroupType}, Tag{100, EndGroupType},
225 }),
226 },
227 msgDesc: msgDesc,
228 wantOutSource: `protopack.Message{
229 protopack.Tag{13, protopack.BytesType}, protopack.LengthPrefix(protopack.Message{
230 protopack.Tag{100, protopack.VarintType}, protopack.Uvarint(18446744073709551615),
231 protopack.Tag{100, protopack.Fixed32Type}, protopack.Uint32(4294967295),
232 protopack.Tag{100, protopack.Fixed64Type}, protopack.Uint64(18446744073709551615),
233 protopack.Tag{100, protopack.BytesType}, protopack.Bytes("bytes"),
234 protopack.Tag{100, protopack.StartGroupType},
235 protopack.Tag{100, protopack.EndGroupType},
236 }),
237 }`,
238 }, {
239 raw: dhex("6a28a006ffffffffffffffffff01a506ffffffffa106ffffffffffffffffa206056279746573a306a406"),
240 msg: Message{
241 Tag{13, BytesType}, LengthPrefix(Message{
242 Tag{100, VarintType}, Uvarint(math.MaxUint64),
243 Tag{100, Fixed32Type}, Uint32(math.MaxUint32),
244 Tag{100, Fixed64Type}, Uint64(math.MaxUint64),
245 Tag{100, BytesType}, Bytes("bytes"),
246 Tag{100, StartGroupType}, Tag{100, EndGroupType},
247 }),
248 },
249 inferMsg: true,
250 }, {
251 raw: dhex("6a28a006ffffffffffffffffff01a506ffffffffa106ffffffffffffffffa206056279746573a306ac06"),
252 msg: Message{
253 Tag{13, BytesType}, Bytes(Message{
254 Tag{100, VarintType}, Uvarint(math.MaxUint64),
255 Tag{100, Fixed32Type}, Uint32(math.MaxUint32),
256 Tag{100, Fixed64Type}, Uint64(math.MaxUint64),
257 Tag{100, BytesType}, Bytes("bytes"),
258 Tag{100, StartGroupType}, Tag{101, EndGroupType},
259 }.Marshal()),
260 },
261 inferMsg: true,
262 }, {
263 raw: dhex("6aa88080808000a006ffffffffffffffffff01a506ffffffffa106ffffffffffffffffa206056279746573a306a406"),
264 msg: Message{
265 Tag{13, BytesType}, Denormalized{5, LengthPrefix(Message{
266 Tag{100, VarintType}, Uvarint(math.MaxUint64),
267 Tag{100, Fixed32Type}, Uint32(math.MaxUint32),
268 Tag{100, Fixed64Type}, Uint64(math.MaxUint64),
269 Tag{100, BytesType}, Bytes("bytes"),
270 Tag{100, StartGroupType}, Tag{100, EndGroupType},
271 })},
272 },
273 msgDesc: msgDesc,
274 wantOutCompact: `Message{Tag{13, Bytes}, Denormalized{+5, LengthPrefix(Message{Tag{100, Varint}, Uvarint(18446744073709551615), Tag{100, Fixed32}, Uint32(4294967295), Tag{100, Fixed64}, Uint64(18446744073709551615), Tag{100, Bytes}, Bytes("bytes"), Tag{100, StartGroup}, Tag{100, EndGroup}})}}`,
275 }, {
276 raw: dhex("73a006ffffffffffffffffff01a506ffffffffa106ffffffffffffffffa206056279746573a306a40674"),
277 msg: Message{
278 Tag{14, StartGroupType}, Message{
279 Tag{100, VarintType}, Uvarint(math.MaxUint64),
280 Tag{100, Fixed32Type}, Uint32(math.MaxUint32),
281 Tag{100, Fixed64Type}, Uint64(math.MaxUint64),
282 Tag{100, BytesType}, Bytes("bytes"),
283 Tag{100, StartGroupType}, Tag{100, EndGroupType},
284 },
285 Tag{14, EndGroupType},
286 },
287 msgDesc: msgDesc,
288 wantOutMulti: `Message{
289 Tag{14, StartGroup},
290 Message{
291 Tag{100, Varint}, Uvarint(18446744073709551615),
292 Tag{100, Fixed32}, Uint32(4294967295),
293 Tag{100, Fixed64}, Uint64(18446744073709551615),
294 Tag{100, Bytes}, Bytes("bytes"),
295 Tag{100, StartGroup},
296 Tag{100, EndGroup},
297 },
298 Tag{14, EndGroup},
299 }`,
300 }, {
301 raw: dhex("d0faa972cd02a5f09051c2d8aa0d6a26a89c311eddef024b423c0f6f47b64227a1600db56e3f73d4113096c9a88e2b99f2d847516853d76a1a6e9811c85a2ab3"),
302 msg: Message{
303 Tag{29970346, VarintType}, Uvarint(333),
304 Tag{21268228, Fixed32Type}, Uint32(229300418),
305 Tag{13, BytesType}, LengthPrefix(Message{
306 Tag{100805, VarintType}, Uvarint(30),
307 Tag{5883, Fixed32Type}, Uint32(255607371),
308 Tag{13, Type(7)},
309 Raw("G\xb6B'\xa1`\r\xb5n?s\xd4\x110\x96ɨ\x8e+\x99\xf2\xd8GQhS"),
310 }),
311 Tag{1706, Type(7)},
312 Raw("\x1an\x98\x11\xc8Z*\xb3"),
313 },
314 msgDesc: msgDesc,
315 }, {
316 raw: dhex("3d08d0e57f"),
317 msg: Message{
318 Tag{7, Fixed32Type}, Float32(math.Float32frombits(
319
320 func() uint32 { return 0x7fe5d008 }(),
321 )),
322 },
323 msgDesc: msgDesc,
324 wantOutSource: `protopack.Message{
325 protopack.Tag{7, protopack.Fixed32Type}, protopack.Float32(math.Float32frombits(0x7fe5d008)),
326 }`,
327 }, {
328 raw: dhex("51a8d65110771bf97f"),
329 msg: Message{
330 Tag{10, Fixed64Type}, Float64(math.Float64frombits(0x7ff91b771051d6a8)),
331 },
332 msgDesc: msgDesc,
333 wantOutSource: `protopack.Message{
334 protopack.Tag{10, protopack.Fixed64Type}, protopack.Float64(math.Float64frombits(0x7ff91b771051d6a8)),
335 }`,
336 }, {
337 raw: dhex("ab2c14481ab3e9a76d937fb4dd5e6c616ef311f62b7fe888785fca5609ffe81c1064e50dd7a9edb408d317e2891c0d54c719446938d41ab0ccf8e61dc28b0ebb"),
338 msg: Message{
339 Tag{709, StartGroupType},
340 Tag{2, EndGroupType},
341 Tag{9, VarintType}, Uvarint(26),
342 Tag{28655254, StartGroupType},
343 Message{
344 Tag{2034, StartGroupType},
345 Tag{194006, EndGroupType},
346 },
347 Tag{13, EndGroupType},
348 Tag{12, Fixed64Type}, Uint64(9865274810543764334),
349 Tag{15, VarintType}, Uvarint(95),
350 Tag{1385, BytesType}, Bytes("\xff\xe8\x1c\x10d\xe5\rש"),
351 Tag{17229, Fixed32Type}, Uint32(2313295827),
352 Tag{3, EndGroupType},
353 Tag{1, Fixed32Type}, Uint32(1142540116),
354 Tag{13, Fixed64Type}, Uint64(2154683029754926136),
355 Tag{28856, BytesType},
356 Raw("\xbb"),
357 },
358 msgDesc: msgDesc,
359 }, {
360 raw: dhex("29baa4ac1c1e0a20183393bac434b8d3559337ec940050038770eaa9937f98e4"),
361 msg: Message{
362 Tag{5, Fixed64Type}, Uint64(1738400580611384506),
363 Tag{6, StartGroupType},
364 Message{
365 Tag{13771682, StartGroupType},
366 Message{
367 Tag{175415, VarintType}, Uvarint(7059),
368 },
369 Denormalized{+1, Tag{333, EndGroupType}},
370 Tag{10, VarintType}, Uvarint(3),
371 Tag{1792, Type(7)},
372 Raw("꩓\u007f\x98\xe4"),
373 },
374 },
375 msgDesc: msgDesc,
376 }}
377
378 equateFloatBits := cmp.Options{
379 cmp.Comparer(func(x, y Float32) bool {
380 return math.Float32bits(float32(x)) == math.Float32bits(float32(y))
381 }),
382 cmp.Comparer(func(x, y Float64) bool {
383 return math.Float64bits(float64(x)) == math.Float64bits(float64(y))
384 }),
385 }
386 for _, tt := range tests {
387 t.Run("", func(t *testing.T) {
388 var msg Message
389 raw := tt.msg.Marshal()
390 msg.unmarshal(tt.raw, tt.msgDesc, tt.inferMsg)
391
392 if !bytes.Equal(raw, tt.raw) {
393 t.Errorf("Marshal() mismatch:\ngot %x\nwant %x", raw, tt.raw)
394 }
395 if diff := cmp.Diff(tt.msg, msg, equateFloatBits); diff != "" {
396 t.Errorf("Unmarshal() mismatch (-want +got):\n%s", diff)
397 }
398 if got, want := tt.msg.Size(), len(tt.raw); got != want {
399 t.Errorf("Size() = %v, want %v", got, want)
400 }
401 if tt.wantOutCompact != "" {
402 gotOut := fmt.Sprintf("%v", tt.msg)
403 if string(gotOut) != tt.wantOutCompact {
404 t.Errorf("fmt.Sprintf(%q, msg):\ngot: %s\nwant: %s", "%v", gotOut, tt.wantOutCompact)
405 }
406 }
407 if tt.wantOutMulti != "" {
408 gotOut := fmt.Sprintf("%+v", tt.msg)
409 if string(gotOut) != tt.wantOutMulti {
410 t.Errorf("fmt.Sprintf(%q, msg):\ngot: %s\nwant: %s", "%+v", gotOut, tt.wantOutMulti)
411 }
412 }
413 if tt.wantOutSource != "" {
414 gotOut := fmt.Sprintf("%#v", tt.msg)
415 if string(gotOut) != tt.wantOutSource {
416 t.Errorf("fmt.Sprintf(%q, msg):\ngot: %s\nwant: %s", "%#v", gotOut, tt.wantOutSource)
417 }
418 }
419 })
420 }
421 }
422
View as plain text