blob: 6ac901c77825db9a9374c2fc3910f9e228a20bc1 [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 Tsai990b9f52019-03-13 12:56:39 -070014 ptype "github.com/golang/protobuf/v2/internal/prototype"
Joe Tsai01ab2962018-09-21 17:44:00 -070015 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
Joe Tsaie1f8d502018-11-26 18:55:29 -080016 cmp "github.com/google/go-cmp/cmp"
Joe Tsai3ab648c2018-08-15 14:41:30 -070017)
18
19var msgDesc = func() pref.MessageDescriptor {
20 mtyp, err := ptype.NewMessage(&ptype.StandaloneMessage{
21 Syntax: pref.Proto2,
22 FullName: "Message",
23 Fields: []ptype.Field{
Damien Neil232ea152018-12-10 15:14:36 -080024 {Name: "F1", Number: 1, Cardinality: pref.Repeated, Kind: pref.BoolKind, IsPacked: ptype.True},
25 {Name: "F2", Number: 2, Cardinality: pref.Repeated, Kind: pref.Int64Kind, IsPacked: ptype.True},
26 {Name: "F3", Number: 3, Cardinality: pref.Repeated, Kind: pref.Sint64Kind, IsPacked: ptype.True},
27 {Name: "F4", Number: 4, Cardinality: pref.Repeated, Kind: pref.Uint64Kind, IsPacked: ptype.True},
28 {Name: "F5", Number: 5, Cardinality: pref.Repeated, Kind: pref.Fixed32Kind, IsPacked: ptype.True},
29 {Name: "F6", Number: 6, Cardinality: pref.Repeated, Kind: pref.Sfixed32Kind, IsPacked: ptype.True},
30 {Name: "F7", Number: 7, Cardinality: pref.Repeated, Kind: pref.FloatKind, IsPacked: ptype.True},
31 {Name: "F8", Number: 8, Cardinality: pref.Repeated, Kind: pref.Fixed64Kind, IsPacked: ptype.True},
32 {Name: "F9", Number: 9, Cardinality: pref.Repeated, Kind: pref.Sfixed64Kind, IsPacked: ptype.True},
33 {Name: "F10", Number: 10, Cardinality: pref.Repeated, Kind: pref.DoubleKind, IsPacked: ptype.True},
Joe Tsai3ab648c2018-08-15 14:41:30 -070034 {Name: "F11", Number: 11, Cardinality: pref.Optional, Kind: pref.StringKind},
35 {Name: "F12", Number: 12, Cardinality: pref.Optional, Kind: pref.BytesKind},
36 {Name: "F13", Number: 13, Cardinality: pref.Optional, Kind: pref.MessageKind, MessageType: ptype.PlaceholderMessage("Message")},
37 {Name: "F14", Number: 14, Cardinality: pref.Optional, Kind: pref.GroupKind, MessageType: ptype.PlaceholderMessage("Message")}},
38 })
39 if err != nil {
40 panic(err)
41 }
42 return mtyp
43}()
44
Joe Tsai3ab648c2018-08-15 14:41:30 -070045// dhex decodes a hex-string and returns the bytes and panics if s is invalid.
46func dhex(s string) []byte {
47 b, err := hex.DecodeString(s)
48 if err != nil {
49 panic(err)
50 }
51 return b
52}
53
54func TestPack(t *testing.T) {
Damien Neil3fa6d3f2019-02-12 11:10:29 -080055 nan32 := math.Float32frombits(0x7fc00000)
56 nan64 := math.Float64frombits(0x7FF8000000000001)
Joe Tsai3ab648c2018-08-15 14:41:30 -070057 tests := []struct {
58 raw []byte
59 msg Message
60
61 wantOutCompact string
62 wantOutMulti string
63 wantOutSource string
64 }{{
65 raw: dhex("080088808080800002088280808080000a09010002828080808000"),
66 msg: Message{
67 Tag{1, VarintType}, Bool(false),
68 Denormalized{5, Tag{1, VarintType}}, Uvarint(2),
69 Tag{1, VarintType}, Denormalized{5, Uvarint(2)},
70 Tag{1, BytesType}, LengthPrefix{Bool(true), Bool(false), Uvarint(2), Denormalized{5, Uvarint(2)}},
71 },
72 wantOutSource: `pack.Message{
73 pack.Tag{1, pack.VarintType}, pack.Bool(false),
74 pack.Denormalized{+5, pack.Tag{1, pack.VarintType}}, pack.Uvarint(2),
75 pack.Tag{1, pack.VarintType}, pack.Denormalized{+5, pack.Uvarint(2)},
76 pack.Tag{1, pack.BytesType}, pack.LengthPrefix{pack.Bool(true), pack.Bool(false), pack.Uvarint(2), pack.Denormalized{+5, pack.Uvarint(2)}},
77}`,
78 }, {
79 raw: dhex("100010828080808000121980808080808080808001ffffffffffffffff7f828080808000"),
80 msg: Message{
81 Tag{2, VarintType}, Varint(0),
82 Tag{2, VarintType}, Denormalized{5, Varint(2)},
83 Tag{2, BytesType}, LengthPrefix{Varint(math.MinInt64), Varint(math.MaxInt64), Denormalized{5, Varint(2)}},
84 },
85 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)}}}`,
86 }, {
87 raw: dhex("1801188180808080001a1affffffffffffffffff01feffffffffffffffff01818080808000"),
88 msg: Message{
89 Tag{3, VarintType}, Svarint(-1),
90 Tag{3, VarintType}, Denormalized{5, Svarint(-1)},
91 Tag{3, BytesType}, LengthPrefix{Svarint(math.MinInt64), Svarint(math.MaxInt64), Denormalized{5, Svarint(-1)}},
92 },
93 wantOutMulti: `Message{
94 Tag{3, Varint}, Svarint(-1),
95 Tag{3, Varint}, Denormalized{+5, Svarint(-1)},
96 Tag{3, Bytes}, LengthPrefix{Svarint(-9223372036854775808), Svarint(9223372036854775807), Denormalized{+5, Svarint(-1)}},
97}`,
98 }, {
99 raw: dhex("200120818080808000221100ffffffffffffffffff01818080808000"),
100 msg: Message{
101 Tag{4, VarintType}, Uvarint(+1),
102 Tag{4, VarintType}, Denormalized{5, Uvarint(+1)},
103 Tag{4, BytesType}, LengthPrefix{Uvarint(0), Uvarint(math.MaxUint64), Denormalized{5, Uvarint(+1)}},
104 },
105 wantOutSource: `pack.Message{
106 pack.Tag{4, pack.VarintType}, pack.Uvarint(1),
107 pack.Tag{4, pack.VarintType}, pack.Denormalized{+5, pack.Uvarint(1)},
108 pack.Tag{4, pack.BytesType}, pack.LengthPrefix{pack.Uvarint(0), pack.Uvarint(18446744073709551615), pack.Denormalized{+5, pack.Uvarint(1)}},
109}`,
110 }, {
111 raw: dhex("2d010000002a0800000000ffffffff"),
112 msg: Message{
113 Tag{5, Fixed32Type}, Uint32(+1),
114 Tag{5, BytesType}, LengthPrefix{Uint32(0), Uint32(math.MaxUint32)},
115 },
116 wantOutCompact: `Message{Tag{5, Fixed32}, Uint32(1), Tag{5, Bytes}, LengthPrefix{Uint32(0), Uint32(4294967295)}}`,
117 }, {
118 raw: dhex("35ffffffff320800000080ffffff7f"),
119 msg: Message{
120 Tag{6, Fixed32Type}, Int32(-1),
121 Tag{6, BytesType}, LengthPrefix{Int32(math.MinInt32), Int32(math.MaxInt32)},
122 },
123 wantOutMulti: `Message{
124 Tag{6, Fixed32}, Int32(-1),
125 Tag{6, Bytes}, LengthPrefix{Int32(-2147483648), Int32(2147483647)},
126}`,
127 }, {
128 raw: dhex("3ddb0f49403a1401000000ffff7f7f0000c07f0000807f000080ff"),
129 msg: Message{
130 Tag{7, Fixed32Type}, Float32(math.Pi),
Damien Neil3fa6d3f2019-02-12 11:10:29 -0800131 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 -0700132 },
133 wantOutSource: `pack.Message{
134 pack.Tag{7, pack.Fixed32Type}, pack.Float32(3.1415927),
135 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))},
136}`,
137 }, {
138 raw: dhex("41010000000000000042100000000000000000ffffffffffffffff"),
139 msg: Message{
140 Tag{8, Fixed64Type}, Uint64(+1),
141 Tag{8, BytesType}, LengthPrefix{Uint64(0), Uint64(math.MaxUint64)},
142 },
143 wantOutCompact: `Message{Tag{8, Fixed64}, Uint64(1), Tag{8, Bytes}, LengthPrefix{Uint64(0), Uint64(18446744073709551615)}}`,
144 }, {
145 raw: dhex("49ffffffffffffffff4a100000000000000080ffffffffffffff7f"),
146 msg: Message{
147 Tag{9, Fixed64Type}, Int64(-1),
148 Tag{9, BytesType}, LengthPrefix{Int64(math.MinInt64), Int64(math.MaxInt64)},
149 },
150 wantOutMulti: `Message{
151 Tag{9, Fixed64}, Int64(-1),
152 Tag{9, Bytes}, LengthPrefix{Int64(-9223372036854775808), Int64(9223372036854775807)},
153}`,
154 }, {
155 raw: dhex("51182d4454fb21094052280100000000000000ffffffffffffef7f010000000000f87f000000000000f07f000000000000f0ff"),
156 msg: Message{
157 Tag{10, Fixed64Type}, Float64(math.Pi),
Damien Neil3fa6d3f2019-02-12 11:10:29 -0800158 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 -0700159 },
160 wantOutMulti: `Message{
161 Tag{10, Fixed64}, Float64(3.141592653589793),
162 Tag{10, Bytes}, LengthPrefix{Float64(5e-324), Float64(1.7976931348623157e+308), Float64(NaN), Float64(+Inf), Float64(-Inf)},
163}`,
164 }, {
165 raw: dhex("5a06737472696e675a868080808000737472696e67"),
166 msg: Message{
167 Tag{11, BytesType}, String("string"),
168 Tag{11, BytesType}, Denormalized{+5, String("string")},
169 },
170 wantOutCompact: `Message{Tag{11, Bytes}, String("string"), Tag{11, Bytes}, Denormalized{+5, String("string")}}`,
171 }, {
172 raw: dhex("62056279746573628580808080006279746573"),
173 msg: Message{
174 Tag{12, BytesType}, Bytes("bytes"),
175 Tag{12, BytesType}, Denormalized{+5, Bytes("bytes")},
176 },
177 wantOutMulti: `Message{
178 Tag{12, Bytes}, Bytes("bytes"),
179 Tag{12, Bytes}, Denormalized{+5, Bytes("bytes")},
180}`,
181 }, {
182 raw: dhex("6a28a006ffffffffffffffffff01a506ffffffffa106ffffffffffffffffa206056279746573a306a406"),
183 msg: Message{
184 Tag{13, BytesType}, LengthPrefix(Message{
185 Tag{100, VarintType}, Uvarint(math.MaxUint64),
186 Tag{100, Fixed32Type}, Uint32(math.MaxUint32),
187 Tag{100, Fixed64Type}, Uint64(math.MaxUint64),
188 Tag{100, BytesType}, Bytes("bytes"),
189 Tag{100, StartGroupType}, Tag{100, EndGroupType},
190 }),
191 },
192 wantOutSource: `pack.Message{
193 pack.Tag{13, pack.BytesType}, pack.LengthPrefix(pack.Message{
194 pack.Tag{100, pack.VarintType}, pack.Uvarint(18446744073709551615),
195 pack.Tag{100, pack.Fixed32Type}, pack.Uint32(4294967295),
196 pack.Tag{100, pack.Fixed64Type}, pack.Uint64(18446744073709551615),
197 pack.Tag{100, pack.BytesType}, pack.Bytes("bytes"),
198 pack.Tag{100, pack.StartGroupType},
199 pack.Tag{100, pack.EndGroupType},
200 }),
201}`,
202 }, {
203 raw: dhex("6aa88080808000a006ffffffffffffffffff01a506ffffffffa106ffffffffffffffffa206056279746573a306a406"),
204 msg: Message{
205 Tag{13, BytesType}, Denormalized{5, LengthPrefix(Message{
206 Tag{100, VarintType}, Uvarint(math.MaxUint64),
207 Tag{100, Fixed32Type}, Uint32(math.MaxUint32),
208 Tag{100, Fixed64Type}, Uint64(math.MaxUint64),
209 Tag{100, BytesType}, Bytes("bytes"),
210 Tag{100, StartGroupType}, Tag{100, EndGroupType},
211 })},
212 },
213 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}})}}`,
214 }, {
215 raw: dhex("73a006ffffffffffffffffff01a506ffffffffa106ffffffffffffffffa206056279746573a306a40674"),
216 msg: Message{
217 Tag{14, StartGroupType}, Message{
218 Tag{100, VarintType}, Uvarint(math.MaxUint64),
219 Tag{100, Fixed32Type}, Uint32(math.MaxUint32),
220 Tag{100, Fixed64Type}, Uint64(math.MaxUint64),
221 Tag{100, BytesType}, Bytes("bytes"),
222 Tag{100, StartGroupType}, Tag{100, EndGroupType},
223 },
224 Tag{14, EndGroupType},
225 },
226 wantOutMulti: `Message{
227 Tag{14, StartGroup},
228 Message{
229 Tag{100, Varint}, Uvarint(18446744073709551615),
230 Tag{100, Fixed32}, Uint32(4294967295),
231 Tag{100, Fixed64}, Uint64(18446744073709551615),
232 Tag{100, Bytes}, Bytes("bytes"),
233 Tag{100, StartGroup},
234 Tag{100, EndGroup},
235 },
236 Tag{14, EndGroup},
237}`,
238 }, {
239 raw: dhex("d0faa972cd02a5f09051c2d8aa0d6a26a89c311eddef024b423c0f6f47b64227a1600db56e3f73d4113096c9a88e2b99f2d847516853d76a1a6e9811c85a2ab3"),
240 msg: Message{
241 Tag{29970346, VarintType}, Uvarint(333),
242 Tag{21268228, Fixed32Type}, Uint32(229300418),
243 Tag{13, BytesType}, LengthPrefix(Message{
244 Tag{100805, VarintType}, Uvarint(30),
245 Tag{5883, Fixed32Type}, Uint32(255607371),
246 Tag{13, Type(7)},
247 Raw("G\xb6B'\xa1`\r\xb5n?s\xd4\x110\x96ɨ\x8e+\x99\xf2\xd8GQhS"),
248 }),
249 Tag{1706, Type(7)},
250 Raw("\x1an\x98\x11\xc8Z*\xb3"),
251 },
252 }, {
253 raw: dhex("3d08d0e57f"),
254 msg: Message{
255 Tag{7, Fixed32Type}, Float32(math.Float32frombits(
256 // TODO: Remove workaround for compiler bug (see https://golang.org/issues/27193).
257 func() uint32 { return 0x7fe5d008 }(),
258 )),
259 },
260 wantOutSource: `pack.Message{
261 pack.Tag{7, pack.Fixed32Type}, pack.Float32(math.Float32frombits(0x7fe5d008)),
262}`,
263 }, {
264 raw: dhex("51a8d65110771bf97f"),
265 msg: Message{
266 Tag{10, Fixed64Type}, Float64(math.Float64frombits(0x7ff91b771051d6a8)),
267 },
268 wantOutSource: `pack.Message{
269 pack.Tag{10, pack.Fixed64Type}, pack.Float64(math.Float64frombits(0x7ff91b771051d6a8)),
270}`,
271 }, {
272 raw: dhex("ab2c14481ab3e9a76d937fb4dd5e6c616ef311f62b7fe888785fca5609ffe81c1064e50dd7a9edb408d317e2891c0d54c719446938d41ab0ccf8e61dc28b0ebb"),
273 msg: Message{
274 Tag{709, StartGroupType},
275 Tag{2, EndGroupType},
276 Tag{9, VarintType}, Uvarint(26),
277 Tag{28655254, StartGroupType},
278 Message{
279 Tag{2034, StartGroupType},
280 Tag{194006, EndGroupType},
281 },
282 Tag{13, EndGroupType},
283 Tag{12, Fixed64Type}, Uint64(9865274810543764334),
284 Tag{15, VarintType}, Uvarint(95),
285 Tag{1385, BytesType}, Bytes("\xff\xe8\x1c\x10d\xe5\rש"),
286 Tag{17229, Fixed32Type}, Uint32(2313295827),
287 Tag{3, EndGroupType},
288 Tag{1, Fixed32Type}, Uint32(1142540116),
289 Tag{13, Fixed64Type}, Uint64(2154683029754926136),
290 Tag{28856, BytesType},
291 Raw("\xbb"),
292 },
293 }, {
294 raw: dhex("29baa4ac1c1e0a20183393bac434b8d3559337ec940050038770eaa9937f98e4"),
295 msg: Message{
296 Tag{5, Fixed64Type}, Uint64(1738400580611384506),
297 Tag{6, StartGroupType},
298 Message{
299 Tag{13771682, StartGroupType},
300 Message{
301 Tag{175415, VarintType}, Uvarint(7059),
302 },
303 Denormalized{+1, Tag{333, EndGroupType}},
304 Tag{10, VarintType}, Uvarint(3),
305 Tag{1792, Type(7)},
306 Raw("꩓\u007f\x98\xe4"),
307 },
308 },
309 }}
310
311 equateFloatBits := cmp.Options{
312 cmp.Comparer(func(x, y Float32) bool {
313 return math.Float32bits(float32(x)) == math.Float32bits(float32(y))
314 }),
315 cmp.Comparer(func(x, y Float64) bool {
316 return math.Float64bits(float64(x)) == math.Float64bits(float64(y))
317 }),
318 }
319 for _, tt := range tests {
320 t.Run("", func(t *testing.T) {
321 var msg Message
322 raw := tt.msg.Marshal()
323 msg.UnmarshalDescriptor(tt.raw, msgDesc)
324
325 if !bytes.Equal(raw, tt.raw) {
326 t.Errorf("Marshal() mismatch:\ngot %x\nwant %x", raw, tt.raw)
327 }
328 if !cmp.Equal(msg, tt.msg, equateFloatBits) {
329 t.Errorf("Unmarshal() mismatch:\ngot %+v\nwant %+v", msg, tt.msg)
330 }
331 if got, want := tt.msg.Size(), len(tt.raw); got != want {
332 t.Errorf("Size() = %v, want %v", got, want)
333 }
334 if tt.wantOutCompact != "" {
335 gotOut := fmt.Sprintf("%v", tt.msg)
336 if string(gotOut) != tt.wantOutCompact {
337 t.Errorf("fmt.Sprintf(%q, msg):\ngot: %s\nwant: %s", "%v", gotOut, tt.wantOutCompact)
338 }
339 }
340 if tt.wantOutMulti != "" {
341 gotOut := fmt.Sprintf("%+v", tt.msg)
342 if string(gotOut) != tt.wantOutMulti {
343 t.Errorf("fmt.Sprintf(%q, msg):\ngot: %s\nwant: %s", "%+v", gotOut, tt.wantOutMulti)
344 }
345 }
346 if tt.wantOutSource != "" {
347 gotOut := fmt.Sprintf("%#v", tt.msg)
348 if string(gotOut) != tt.wantOutSource {
349 t.Errorf("fmt.Sprintf(%q, msg):\ngot: %s\nwant: %s", "%#v", gotOut, tt.wantOutSource)
350 }
351 }
352 })
353 }
354}