1
2
3
4
5 package binary
6
7 import (
8 "bytes"
9 "fmt"
10 "io"
11 "math"
12 "reflect"
13 "strings"
14 "sync"
15 "testing"
16 )
17
18 type Struct struct {
19 Int8 int8
20 Int16 int16
21 Int32 int32
22 Int64 int64
23 Uint8 uint8
24 Uint16 uint16
25 Uint32 uint32
26 Uint64 uint64
27 Float32 float32
28 Float64 float64
29 Complex64 complex64
30 Complex128 complex128
31 Array [4]uint8
32 Bool bool
33 BoolArray [4]bool
34 }
35
36 type T struct {
37 Int int
38 Uint uint
39 Uintptr uintptr
40 Array [4]int
41 }
42
43 var s = Struct{
44 0x01,
45 0x0203,
46 0x04050607,
47 0x08090a0b0c0d0e0f,
48 0x10,
49 0x1112,
50 0x13141516,
51 0x1718191a1b1c1d1e,
52
53 math.Float32frombits(0x1f202122),
54 math.Float64frombits(0x232425262728292a),
55 complex(
56 math.Float32frombits(0x2b2c2d2e),
57 math.Float32frombits(0x2f303132),
58 ),
59 complex(
60 math.Float64frombits(0x333435363738393a),
61 math.Float64frombits(0x3b3c3d3e3f404142),
62 ),
63
64 [4]uint8{0x43, 0x44, 0x45, 0x46},
65
66 true,
67 [4]bool{true, false, true, false},
68 }
69
70 var big = []byte{
71 1,
72 2, 3,
73 4, 5, 6, 7,
74 8, 9, 10, 11, 12, 13, 14, 15,
75 16,
76 17, 18,
77 19, 20, 21, 22,
78 23, 24, 25, 26, 27, 28, 29, 30,
79
80 31, 32, 33, 34,
81 35, 36, 37, 38, 39, 40, 41, 42,
82 43, 44, 45, 46, 47, 48, 49, 50,
83 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
84
85 67, 68, 69, 70,
86
87 1,
88 1, 0, 1, 0,
89 }
90
91 var little = []byte{
92 1,
93 3, 2,
94 7, 6, 5, 4,
95 15, 14, 13, 12, 11, 10, 9, 8,
96 16,
97 18, 17,
98 22, 21, 20, 19,
99 30, 29, 28, 27, 26, 25, 24, 23,
100
101 34, 33, 32, 31,
102 42, 41, 40, 39, 38, 37, 36, 35,
103 46, 45, 44, 43, 50, 49, 48, 47,
104 58, 57, 56, 55, 54, 53, 52, 51, 66, 65, 64, 63, 62, 61, 60, 59,
105
106 67, 68, 69, 70,
107
108 1,
109 1, 0, 1, 0,
110 }
111
112 var src = []byte{1, 2, 3, 4, 5, 6, 7, 8}
113 var res = []int32{0x01020304, 0x05060708}
114 var putbuf = []byte{0, 0, 0, 0, 0, 0, 0, 0}
115
116 func checkResult(t *testing.T, dir string, order ByteOrder, err error, have, want interface{}) {
117 if err != nil {
118 t.Errorf("%v %v: %v", dir, order, err)
119 return
120 }
121 if !reflect.DeepEqual(have, want) {
122 t.Errorf("%v %v:\n\thave %+v\n\twant %+v", dir, order, have, want)
123 }
124 }
125
126 func testRead(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {
127 var s2 Struct
128 err := Read(bytes.NewReader(b), order, &s2)
129 checkResult(t, "Read", order, err, s2, s1)
130 }
131
132 func testWrite(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {
133 buf := new(bytes.Buffer)
134 err := Write(buf, order, s1)
135 checkResult(t, "Write", order, err, buf.Bytes(), b)
136 }
137
138 func TestLittleEndianRead(t *testing.T) { testRead(t, LittleEndian, little, s) }
139 func TestLittleEndianWrite(t *testing.T) { testWrite(t, LittleEndian, little, s) }
140 func TestLittleEndianPtrWrite(t *testing.T) { testWrite(t, LittleEndian, little, &s) }
141
142 func TestBigEndianRead(t *testing.T) { testRead(t, BigEndian, big, s) }
143 func TestBigEndianWrite(t *testing.T) { testWrite(t, BigEndian, big, s) }
144 func TestBigEndianPtrWrite(t *testing.T) { testWrite(t, BigEndian, big, &s) }
145
146 func TestReadSlice(t *testing.T) {
147 slice := make([]int32, 2)
148 err := Read(bytes.NewReader(src), BigEndian, slice)
149 checkResult(t, "ReadSlice", BigEndian, err, slice, res)
150 }
151
152 func TestWriteSlice(t *testing.T) {
153 buf := new(bytes.Buffer)
154 err := Write(buf, BigEndian, res)
155 checkResult(t, "WriteSlice", BigEndian, err, buf.Bytes(), src)
156 }
157
158 func TestReadBool(t *testing.T) {
159 var res bool
160 var err error
161 err = Read(bytes.NewReader([]byte{0}), BigEndian, &res)
162 checkResult(t, "ReadBool", BigEndian, err, res, false)
163 res = false
164 err = Read(bytes.NewReader([]byte{1}), BigEndian, &res)
165 checkResult(t, "ReadBool", BigEndian, err, res, true)
166 res = false
167 err = Read(bytes.NewReader([]byte{2}), BigEndian, &res)
168 checkResult(t, "ReadBool", BigEndian, err, res, true)
169 }
170
171 func TestReadBoolSlice(t *testing.T) {
172 slice := make([]bool, 4)
173 err := Read(bytes.NewReader([]byte{0, 1, 2, 255}), BigEndian, slice)
174 checkResult(t, "ReadBoolSlice", BigEndian, err, slice, []bool{false, true, true, true})
175 }
176
177
178 var intArrays = []interface{}{
179 &[100]int8{},
180 &[100]int16{},
181 &[100]int32{},
182 &[100]int64{},
183 &[100]uint8{},
184 &[100]uint16{},
185 &[100]uint32{},
186 &[100]uint64{},
187 }
188
189 func TestSliceRoundTrip(t *testing.T) {
190 buf := new(bytes.Buffer)
191 for _, array := range intArrays {
192 src := reflect.ValueOf(array).Elem()
193 unsigned := false
194 switch src.Index(0).Kind() {
195 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
196 unsigned = true
197 }
198 for i := 0; i < src.Len(); i++ {
199 if unsigned {
200 src.Index(i).SetUint(uint64(i * 0x07654321))
201 } else {
202 src.Index(i).SetInt(int64(i * 0x07654321))
203 }
204 }
205 buf.Reset()
206 srcSlice := src.Slice(0, src.Len())
207 err := Write(buf, BigEndian, srcSlice.Interface())
208 if err != nil {
209 t.Fatal(err)
210 }
211 dst := reflect.New(src.Type()).Elem()
212 dstSlice := dst.Slice(0, dst.Len())
213 err = Read(buf, BigEndian, dstSlice.Interface())
214 if err != nil {
215 t.Fatal(err)
216 }
217 if !reflect.DeepEqual(src.Interface(), dst.Interface()) {
218 t.Fatal(src)
219 }
220 }
221 }
222
223 func TestWriteT(t *testing.T) {
224 buf := new(bytes.Buffer)
225 ts := T{}
226 if err := Write(buf, BigEndian, ts); err == nil {
227 t.Errorf("WriteT: have err == nil, want non-nil")
228 }
229
230 tv := reflect.Indirect(reflect.ValueOf(ts))
231 for i, n := 0, tv.NumField(); i < n; i++ {
232 typ := tv.Field(i).Type().String()
233 if typ == "[4]int" {
234 typ = "int"
235 }
236 if err := Write(buf, BigEndian, tv.Field(i).Interface()); err == nil {
237 t.Errorf("WriteT.%v: have err == nil, want non-nil", tv.Field(i).Type())
238 } else if !strings.Contains(err.Error(), typ) {
239 t.Errorf("WriteT: have err == %q, want it to mention %s", err, typ)
240 }
241 }
242 }
243
244 type BlankFields struct {
245 A uint32
246 _ int32
247 B float64
248 _ [4]int16
249 C byte
250 _ [7]byte
251 _ struct {
252 f [8]float32
253 }
254 }
255
256 type BlankFieldsProbe struct {
257 A uint32
258 P0 int32
259 B float64
260 P1 [4]int16
261 C byte
262 P2 [7]byte
263 P3 struct {
264 F [8]float32
265 }
266 }
267
268 func TestBlankFields(t *testing.T) {
269 buf := new(bytes.Buffer)
270 b1 := BlankFields{A: 1234567890, B: 2.718281828, C: 42}
271 if err := Write(buf, LittleEndian, &b1); err != nil {
272 t.Error(err)
273 }
274
275
276 var p BlankFieldsProbe
277 if err := Read(buf, LittleEndian, &p); err != nil {
278 t.Error(err)
279 }
280
281
282 if p.P0 != 0 || p.P1[0] != 0 || p.P2[0] != 0 || p.P3.F[0] != 0 {
283 t.Errorf("non-zero values for originally blank fields: %#v", p)
284 }
285
286
287 if err := Write(buf, LittleEndian, &p); err != nil {
288 t.Error(err)
289 }
290
291
292 var b2 BlankFields
293 if err := Read(buf, LittleEndian, &b2); err != nil {
294 t.Error(err)
295 }
296 if b1.A != b2.A || b1.B != b2.B || b1.C != b2.C {
297 t.Errorf("%#v != %#v", b1, b2)
298 }
299 }
300
301 func TestSizeStructCache(t *testing.T) {
302
303 structSize = sync.Map{}
304
305 count := func() int {
306 var i int
307 structSize.Range(func(_, _ interface{}) bool {
308 i++
309 return true
310 })
311 return i
312 }
313
314 var total int
315 added := func() int {
316 delta := count() - total
317 total += delta
318 return delta
319 }
320
321 type foo struct {
322 A uint32
323 }
324
325 type bar struct {
326 A Struct
327 B foo
328 C Struct
329 }
330
331 testcases := []struct {
332 val interface{}
333 want int
334 }{
335 {new(foo), 1},
336 {new(bar), 1},
337 {new(bar), 0},
338 {new(struct{ A Struct }), 1},
339 {new(struct{ A Struct }), 0},
340 }
341
342 for _, tc := range testcases {
343 if Size(tc.val) == -1 {
344 t.Fatalf("Can't get the size of %T", tc.val)
345 }
346
347 if n := added(); n != tc.want {
348 t.Errorf("Sizing %T added %d entries to the cache, want %d", tc.val, n, tc.want)
349 }
350 }
351 }
352
353
354
355
356
357 type Unexported struct {
358 a int32
359 }
360
361 func TestUnexportedRead(t *testing.T) {
362 var buf bytes.Buffer
363 u1 := Unexported{a: 1}
364 if err := Write(&buf, LittleEndian, &u1); err != nil {
365 t.Fatal(err)
366 }
367
368 defer func() {
369 if recover() == nil {
370 t.Fatal("did not panic")
371 }
372 }()
373 var u2 Unexported
374 Read(&buf, LittleEndian, &u2)
375 }
376
377 func TestReadErrorMsg(t *testing.T) {
378 var buf bytes.Buffer
379 read := func(data interface{}) {
380 err := Read(&buf, LittleEndian, data)
381 want := "binary.Read: invalid type " + reflect.TypeOf(data).String()
382 if err == nil {
383 t.Errorf("%T: got no error; want %q", data, want)
384 return
385 }
386 if got := err.Error(); got != want {
387 t.Errorf("%T: got %q; want %q", data, got, want)
388 }
389 }
390 read(0)
391 s := new(struct{})
392 read(&s)
393 p := &s
394 read(&p)
395 }
396
397 func TestReadTruncated(t *testing.T) {
398 const data = "0123456789abcdef"
399
400 var b1 = make([]int32, 4)
401 var b2 struct {
402 A, B, C, D byte
403 E int32
404 F float64
405 }
406
407 for i := 0; i <= len(data); i++ {
408 var errWant error
409 switch i {
410 case 0:
411 errWant = io.EOF
412 case len(data):
413 errWant = nil
414 default:
415 errWant = io.ErrUnexpectedEOF
416 }
417
418 if err := Read(strings.NewReader(data[:i]), LittleEndian, &b1); err != errWant {
419 t.Errorf("Read(%d) with slice: got %v, want %v", i, err, errWant)
420 }
421 if err := Read(strings.NewReader(data[:i]), LittleEndian, &b2); err != errWant {
422 t.Errorf("Read(%d) with struct: got %v, want %v", i, err, errWant)
423 }
424 }
425 }
426
427 func testUint64SmallSliceLengthPanics() (panicked bool) {
428 defer func() {
429 panicked = recover() != nil
430 }()
431 b := [8]byte{1, 2, 3, 4, 5, 6, 7, 8}
432 LittleEndian.Uint64(b[:4])
433 return false
434 }
435
436 func testPutUint64SmallSliceLengthPanics() (panicked bool) {
437 defer func() {
438 panicked = recover() != nil
439 }()
440 b := [8]byte{}
441 LittleEndian.PutUint64(b[:4], 0x0102030405060708)
442 return false
443 }
444
445 func TestEarlyBoundsChecks(t *testing.T) {
446 if testUint64SmallSliceLengthPanics() != true {
447 t.Errorf("binary.LittleEndian.Uint64 expected to panic for small slices, but didn't")
448 }
449 if testPutUint64SmallSliceLengthPanics() != true {
450 t.Errorf("binary.LittleEndian.PutUint64 expected to panic for small slices, but didn't")
451 }
452 }
453
454 func TestReadInvalidDestination(t *testing.T) {
455 testReadInvalidDestination(t, BigEndian)
456 testReadInvalidDestination(t, LittleEndian)
457 }
458
459 func testReadInvalidDestination(t *testing.T, order ByteOrder) {
460 destinations := []interface{}{
461 int8(0),
462 int16(0),
463 int32(0),
464 int64(0),
465
466 uint8(0),
467 uint16(0),
468 uint32(0),
469 uint64(0),
470
471 bool(false),
472 }
473
474 for _, dst := range destinations {
475 err := Read(bytes.NewReader([]byte{1, 2, 3, 4, 5, 6, 7, 8}), order, dst)
476 want := fmt.Sprintf("binary.Read: invalid type %T", dst)
477 if err == nil || err.Error() != want {
478 t.Fatalf("for type %T: got %q; want %q", dst, err, want)
479 }
480 }
481 }
482
483 type byteSliceReader struct {
484 remain []byte
485 }
486
487 func (br *byteSliceReader) Read(p []byte) (int, error) {
488 n := copy(p, br.remain)
489 br.remain = br.remain[n:]
490 return n, nil
491 }
492
493 func BenchmarkReadSlice1000Int32s(b *testing.B) {
494 bsr := &byteSliceReader{}
495 slice := make([]int32, 1000)
496 buf := make([]byte, len(slice)*4)
497 b.SetBytes(int64(len(buf)))
498 b.ResetTimer()
499 for i := 0; i < b.N; i++ {
500 bsr.remain = buf
501 Read(bsr, BigEndian, slice)
502 }
503 }
504
505 func BenchmarkReadStruct(b *testing.B) {
506 bsr := &byteSliceReader{}
507 var buf bytes.Buffer
508 Write(&buf, BigEndian, &s)
509 b.SetBytes(int64(dataSize(reflect.ValueOf(s))))
510 t := s
511 b.ResetTimer()
512 for i := 0; i < b.N; i++ {
513 bsr.remain = buf.Bytes()
514 Read(bsr, BigEndian, &t)
515 }
516 b.StopTimer()
517 if b.N > 0 && !reflect.DeepEqual(s, t) {
518 b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", t, s)
519 }
520 }
521
522 func BenchmarkWriteStruct(b *testing.B) {
523 b.SetBytes(int64(Size(&s)))
524 b.ResetTimer()
525 for i := 0; i < b.N; i++ {
526 Write(io.Discard, BigEndian, &s)
527 }
528 }
529
530 func BenchmarkReadInts(b *testing.B) {
531 var ls Struct
532 bsr := &byteSliceReader{}
533 var r io.Reader = bsr
534 b.SetBytes(2 * (1 + 2 + 4 + 8))
535 b.ResetTimer()
536 for i := 0; i < b.N; i++ {
537 bsr.remain = big
538 Read(r, BigEndian, &ls.Int8)
539 Read(r, BigEndian, &ls.Int16)
540 Read(r, BigEndian, &ls.Int32)
541 Read(r, BigEndian, &ls.Int64)
542 Read(r, BigEndian, &ls.Uint8)
543 Read(r, BigEndian, &ls.Uint16)
544 Read(r, BigEndian, &ls.Uint32)
545 Read(r, BigEndian, &ls.Uint64)
546 }
547 b.StopTimer()
548 want := s
549 want.Float32 = 0
550 want.Float64 = 0
551 want.Complex64 = 0
552 want.Complex128 = 0
553 want.Array = [4]uint8{0, 0, 0, 0}
554 want.Bool = false
555 want.BoolArray = [4]bool{false, false, false, false}
556 if b.N > 0 && !reflect.DeepEqual(ls, want) {
557 b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", ls, want)
558 }
559 }
560
561 func BenchmarkWriteInts(b *testing.B) {
562 buf := new(bytes.Buffer)
563 var w io.Writer = buf
564 b.SetBytes(2 * (1 + 2 + 4 + 8))
565 b.ResetTimer()
566 for i := 0; i < b.N; i++ {
567 buf.Reset()
568 Write(w, BigEndian, s.Int8)
569 Write(w, BigEndian, s.Int16)
570 Write(w, BigEndian, s.Int32)
571 Write(w, BigEndian, s.Int64)
572 Write(w, BigEndian, s.Uint8)
573 Write(w, BigEndian, s.Uint16)
574 Write(w, BigEndian, s.Uint32)
575 Write(w, BigEndian, s.Uint64)
576 }
577 b.StopTimer()
578 if b.N > 0 && !bytes.Equal(buf.Bytes(), big[:30]) {
579 b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30])
580 }
581 }
582
583 func BenchmarkWriteSlice1000Int32s(b *testing.B) {
584 slice := make([]int32, 1000)
585 buf := new(bytes.Buffer)
586 var w io.Writer = buf
587 b.SetBytes(4 * 1000)
588 b.ResetTimer()
589 for i := 0; i < b.N; i++ {
590 buf.Reset()
591 Write(w, BigEndian, slice)
592 }
593 b.StopTimer()
594 }
595
596 func BenchmarkPutUint16(b *testing.B) {
597 b.SetBytes(2)
598 for i := 0; i < b.N; i++ {
599 BigEndian.PutUint16(putbuf[:], uint16(i))
600 }
601 }
602
603 func BenchmarkPutUint32(b *testing.B) {
604 b.SetBytes(4)
605 for i := 0; i < b.N; i++ {
606 BigEndian.PutUint32(putbuf[:], uint32(i))
607 }
608 }
609
610 func BenchmarkPutUint64(b *testing.B) {
611 b.SetBytes(8)
612 for i := 0; i < b.N; i++ {
613 BigEndian.PutUint64(putbuf[:], uint64(i))
614 }
615 }
616 func BenchmarkLittleEndianPutUint16(b *testing.B) {
617 b.SetBytes(2)
618 for i := 0; i < b.N; i++ {
619 LittleEndian.PutUint16(putbuf[:], uint16(i))
620 }
621 }
622
623 func BenchmarkLittleEndianPutUint32(b *testing.B) {
624 b.SetBytes(4)
625 for i := 0; i < b.N; i++ {
626 LittleEndian.PutUint32(putbuf[:], uint32(i))
627 }
628 }
629
630 func BenchmarkLittleEndianPutUint64(b *testing.B) {
631 b.SetBytes(8)
632 for i := 0; i < b.N; i++ {
633 LittleEndian.PutUint64(putbuf[:], uint64(i))
634 }
635 }
636
637 func BenchmarkReadFloats(b *testing.B) {
638 var ls Struct
639 bsr := &byteSliceReader{}
640 var r io.Reader = bsr
641 b.SetBytes(4 + 8)
642 b.ResetTimer()
643 for i := 0; i < b.N; i++ {
644 bsr.remain = big[30:]
645 Read(r, BigEndian, &ls.Float32)
646 Read(r, BigEndian, &ls.Float64)
647 }
648 b.StopTimer()
649 want := s
650 want.Int8 = 0
651 want.Int16 = 0
652 want.Int32 = 0
653 want.Int64 = 0
654 want.Uint8 = 0
655 want.Uint16 = 0
656 want.Uint32 = 0
657 want.Uint64 = 0
658 want.Complex64 = 0
659 want.Complex128 = 0
660 want.Array = [4]uint8{0, 0, 0, 0}
661 want.Bool = false
662 want.BoolArray = [4]bool{false, false, false, false}
663 if b.N > 0 && !reflect.DeepEqual(ls, want) {
664 b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", ls, want)
665 }
666 }
667
668 func BenchmarkWriteFloats(b *testing.B) {
669 buf := new(bytes.Buffer)
670 var w io.Writer = buf
671 b.SetBytes(4 + 8)
672 b.ResetTimer()
673 for i := 0; i < b.N; i++ {
674 buf.Reset()
675 Write(w, BigEndian, s.Float32)
676 Write(w, BigEndian, s.Float64)
677 }
678 b.StopTimer()
679 if b.N > 0 && !bytes.Equal(buf.Bytes(), big[30:30+4+8]) {
680 b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[30:30+4+8])
681 }
682 }
683
684 func BenchmarkReadSlice1000Float32s(b *testing.B) {
685 bsr := &byteSliceReader{}
686 slice := make([]float32, 1000)
687 buf := make([]byte, len(slice)*4)
688 b.SetBytes(int64(len(buf)))
689 b.ResetTimer()
690 for i := 0; i < b.N; i++ {
691 bsr.remain = buf
692 Read(bsr, BigEndian, slice)
693 }
694 }
695
696 func BenchmarkWriteSlice1000Float32s(b *testing.B) {
697 slice := make([]float32, 1000)
698 buf := new(bytes.Buffer)
699 var w io.Writer = buf
700 b.SetBytes(4 * 1000)
701 b.ResetTimer()
702 for i := 0; i < b.N; i++ {
703 buf.Reset()
704 Write(w, BigEndian, slice)
705 }
706 b.StopTimer()
707 }
708
709 func BenchmarkReadSlice1000Uint8s(b *testing.B) {
710 bsr := &byteSliceReader{}
711 slice := make([]uint8, 1000)
712 buf := make([]byte, len(slice))
713 b.SetBytes(int64(len(buf)))
714 b.ResetTimer()
715 for i := 0; i < b.N; i++ {
716 bsr.remain = buf
717 Read(bsr, BigEndian, slice)
718 }
719 }
720
721 func BenchmarkWriteSlice1000Uint8s(b *testing.B) {
722 slice := make([]uint8, 1000)
723 buf := new(bytes.Buffer)
724 var w io.Writer = buf
725 b.SetBytes(1000)
726 b.ResetTimer()
727 for i := 0; i < b.N; i++ {
728 buf.Reset()
729 Write(w, BigEndian, slice)
730 }
731 }
732
View as plain text