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