1 // Copyright 2009 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.
53 math
.Float32frombits(0x1f202122),
54 math
.Float64frombits(0x232425262728292a),
56 math
.Float32frombits(0x2b2c2d2e),
57 math
.Float32frombits(0x2f303132),
60 math
.Float64frombits(0x333435363738393a),
61 math
.Float64frombits(0x3b3c3d3e3f404142),
64 [4]uint8{0x43, 0x44, 0x45, 0x46},
67 [4]bool{true, false, true, false},
74 8, 9, 10, 11, 12, 13, 14, 15,
78 23, 24, 25, 26, 27, 28, 29, 30,
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,
95 15, 14, 13, 12, 11, 10, 9, 8,
99 30, 29, 28, 27, 26, 25, 24, 23,
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,
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}
116 func checkResult(t
*testing
.T
, dir
string, order ByteOrder
, err error
, have
, want any
) {
118 t
.Errorf("%v %v: %v", dir
, order
, err
)
121 if !reflect
.DeepEqual(have
, want
) {
122 t
.Errorf("%v %v:\n\thave %+v\n\twant %+v", dir
, order
, have
, want
)
126 func testRead(t
*testing
.T
, order ByteOrder
, b
[]byte, s1 any
) {
128 err
:= Read(bytes
.NewReader(b
), order
, &s2
)
129 checkResult(t
, "Read", order
, err
, s2
, s1
)
132 func testWrite(t
*testing
.T
, order ByteOrder
, b
[]byte, s1 any
) {
133 buf
:= new(bytes
.Buffer
)
134 err
:= Write(buf
, order
, s1
)
135 checkResult(t
, "Write", order
, err
, buf
.Bytes(), b
)
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
) }
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
) }
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
)
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
)
158 func TestReadBool(t
*testing
.T
) {
161 err
= Read(bytes
.NewReader([]byte{0}), BigEndian
, &res
)
162 checkResult(t
, "ReadBool", BigEndian
, err
, res
, false)
164 err
= Read(bytes
.NewReader([]byte{1}), BigEndian
, &res
)
165 checkResult(t
, "ReadBool", BigEndian
, err
, res
, true)
167 err
= Read(bytes
.NewReader([]byte{2}), BigEndian
, &res
)
168 checkResult(t
, "ReadBool", BigEndian
, err
, res
, true)
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})
177 // Addresses of arrays are easier to manipulate with reflection than are slices.
178 var intArrays
= []any
{
189 func TestSliceRoundTrip(t
*testing
.T
) {
190 buf
:= new(bytes
.Buffer
)
191 for _
, array
:= range intArrays
{
192 src
:= reflect
.ValueOf(array
).Elem()
194 switch src
.Index(0).Kind() {
195 case reflect
.Uint8
, reflect
.Uint16
, reflect
.Uint32
, reflect
.Uint64
:
198 for i
:= 0; i
< src
.Len(); i
++ {
200 src
.Index(i
).SetUint(uint64(i
* 0x07654321))
202 src
.Index(i
).SetInt(int64(i
* 0x07654321))
206 srcSlice
:= src
.Slice(0, src
.Len())
207 err
:= Write(buf
, BigEndian
, srcSlice
.Interface())
211 dst
:= reflect
.New(src
.Type()).Elem()
212 dstSlice
:= dst
.Slice(0, dst
.Len())
213 err
= Read(buf
, BigEndian
, dstSlice
.Interface())
217 if !reflect
.DeepEqual(src
.Interface(), dst
.Interface()) {
223 func TestWriteT(t
*testing
.T
) {
224 buf
:= new(bytes
.Buffer
)
226 if err
:= Write(buf
, BigEndian
, ts
); err
== nil {
227 t
.Errorf("WriteT: have err == nil, want non-nil")
230 tv
:= reflect
.Indirect(reflect
.ValueOf(ts
))
231 for i
, n
:= 0, tv
.NumField(); i
< n
; i
++ {
232 typ
:= tv
.Field(i
).Type().String()
234 typ
= "int" // the problem is int, not the [4]
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
)
244 type BlankFields
struct {
256 type BlankFieldsProbe
struct {
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 {
275 // zero values must have been written for blank fields
276 var p BlankFieldsProbe
277 if err
:= Read(buf
, LittleEndian
, &p
); err
!= nil {
281 // quick test: only check first value of slices
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
)
286 // write p and see if we can probe only some fields
287 if err
:= Write(buf
, LittleEndian
, &p
); err
!= nil {
291 // read should ignore blank fields in b2
293 if err
:= Read(buf
, LittleEndian
, &b2
); err
!= nil {
296 if b1
.A
!= b2
.A || b1
.B
!= b2
.B || b1
.C
!= b2
.C
{
297 t
.Errorf("%#v != %#v", b1
, b2
)
301 func TestSizeStructCache(t
*testing
.T
) {
302 // Reset the cache, otherwise multiple test runs fail.
303 structSize
= sync
.Map
{}
305 count
:= func() int {
307 structSize
.Range(func(_
, _ any
) bool {
315 added
:= func() int {
316 delta
:= count() - total
331 testcases
:= []struct {
338 {new(struct{ A Struct
}), 1},
339 {new(struct{ A Struct
}), 0},
342 for _
, tc
:= range testcases
{
343 if Size(tc
.val
) == -1 {
344 t
.Fatalf("Can't get the size of %T", tc
.val
)
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
)
353 // An attempt to read into a struct with an unexported field will
354 // panic. This is probably not the best choice, but at this point
355 // anything else would be an API change.
357 type Unexported
struct {
361 func TestUnexportedRead(t
*testing
.T
) {
363 u1
:= Unexported
{a
: 1}
364 if err
:= Write(&buf
, LittleEndian
, &u1
); err
!= nil {
369 if recover() == nil {
370 t
.Fatal("did not panic")
374 Read(&buf
, LittleEndian
, &u2
)
377 func TestReadErrorMsg(t
*testing
.T
) {
379 read
:= func(data any
) {
380 err
:= Read(&buf
, LittleEndian
, data
)
381 want
:= "binary.Read: invalid type " + reflect
.TypeOf(data
).String()
383 t
.Errorf("%T: got no error; want %q", data
, want
)
386 if got
:= err
.Error(); got
!= want
{
387 t
.Errorf("%T: got %q; want %q", data
, got
, want
)
397 func TestReadTruncated(t
*testing
.T
) {
398 const data
= "0123456789abcdef"
400 var b1
= make([]int32, 4)
407 for i
:= 0; i
<= len(data
); i
++ {
415 errWant
= io
.ErrUnexpectedEOF
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
)
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
)
427 func testUint64SmallSliceLengthPanics() (panicked
bool) {
429 panicked
= recover() != nil
431 b
:= [8]byte{1, 2, 3, 4, 5, 6, 7, 8}
432 LittleEndian
.Uint64(b
[:4])
436 func testPutUint64SmallSliceLengthPanics() (panicked
bool) {
438 panicked
= recover() != nil
441 LittleEndian
.PutUint64(b
[:4], 0x0102030405060708)
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")
449 if testPutUint64SmallSliceLengthPanics() != true {
450 t
.Errorf("binary.LittleEndian.PutUint64 expected to panic for small slices, but didn't")
454 func TestReadInvalidDestination(t
*testing
.T
) {
455 testReadInvalidDestination(t
, BigEndian
)
456 testReadInvalidDestination(t
, LittleEndian
)
459 func testReadInvalidDestination(t
*testing
.T
, order ByteOrder
) {
460 destinations
:= []any
{
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
)
483 type byteSliceReader
struct {
487 func (br
*byteSliceReader
) Read(p
[]byte) (int, error
) {
488 n
:= copy(p
, br
.remain
)
489 br
.remain
= br
.remain
[n
:]
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
)))
499 for i
:= 0; i
< b
.N
; i
++ {
501 Read(bsr
, BigEndian
, slice
)
505 func BenchmarkReadStruct(b
*testing
.B
) {
506 bsr
:= &byteSliceReader
{}
508 Write(&buf
, BigEndian
, &s
)
509 b
.SetBytes(int64(dataSize(reflect
.ValueOf(s
))))
512 for i
:= 0; i
< b
.N
; i
++ {
513 bsr
.remain
= buf
.Bytes()
514 Read(bsr
, BigEndian
, &t
)
517 if b
.N
> 0 && !reflect
.DeepEqual(s
, t
) {
518 b
.Fatalf("struct doesn't match:\ngot %v;\nwant %v", t
, s
)
522 func BenchmarkWriteStruct(b
*testing
.B
) {
523 b
.SetBytes(int64(Size(&s
)))
525 for i
:= 0; i
< b
.N
; i
++ {
526 Write(io
.Discard
, BigEndian
, &s
)
530 func BenchmarkReadInts(b
*testing
.B
) {
532 bsr
:= &byteSliceReader
{}
533 var r io
.Reader
= bsr
534 b
.SetBytes(2 * (1 + 2 + 4 + 8))
536 for i
:= 0; i
< b
.N
; i
++ {
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
)
553 want
.Array
= [4]uint8{0, 0, 0, 0}
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
)
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))
566 for i
:= 0; i
< b
.N
; i
++ {
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
)
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])
583 func BenchmarkWriteSlice1000Int32s(b
*testing
.B
) {
584 slice
:= make([]int32, 1000)
585 buf
:= new(bytes
.Buffer
)
586 var w io
.Writer
= buf
589 for i
:= 0; i
< b
.N
; i
++ {
591 Write(w
, BigEndian
, slice
)
596 func BenchmarkPutUint16(b
*testing
.B
) {
598 for i
:= 0; i
< b
.N
; i
++ {
599 BigEndian
.PutUint16(putbuf
[:], uint16(i
))
603 func BenchmarkPutUint32(b
*testing
.B
) {
605 for i
:= 0; i
< b
.N
; i
++ {
606 BigEndian
.PutUint32(putbuf
[:], uint32(i
))
610 func BenchmarkPutUint64(b
*testing
.B
) {
612 for i
:= 0; i
< b
.N
; i
++ {
613 BigEndian
.PutUint64(putbuf
[:], uint64(i
))
616 func BenchmarkLittleEndianPutUint16(b
*testing
.B
) {
618 for i
:= 0; i
< b
.N
; i
++ {
619 LittleEndian
.PutUint16(putbuf
[:], uint16(i
))
623 func BenchmarkLittleEndianPutUint32(b
*testing
.B
) {
625 for i
:= 0; i
< b
.N
; i
++ {
626 LittleEndian
.PutUint32(putbuf
[:], uint32(i
))
630 func BenchmarkLittleEndianPutUint64(b
*testing
.B
) {
632 for i
:= 0; i
< b
.N
; i
++ {
633 LittleEndian
.PutUint64(putbuf
[:], uint64(i
))
637 func BenchmarkReadFloats(b
*testing
.B
) {
639 bsr
:= &byteSliceReader
{}
640 var r io
.Reader
= bsr
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
)
660 want
.Array
= [4]uint8{0, 0, 0, 0}
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
)
668 func BenchmarkWriteFloats(b
*testing
.B
) {
669 buf
:= new(bytes
.Buffer
)
670 var w io
.Writer
= buf
673 for i
:= 0; i
< b
.N
; i
++ {
675 Write(w
, BigEndian
, s
.Float32
)
676 Write(w
, BigEndian
, s
.Float64
)
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])
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
)))
690 for i
:= 0; i
< b
.N
; i
++ {
692 Read(bsr
, BigEndian
, slice
)
696 func BenchmarkWriteSlice1000Float32s(b
*testing
.B
) {
697 slice
:= make([]float32, 1000)
698 buf
:= new(bytes
.Buffer
)
699 var w io
.Writer
= buf
702 for i
:= 0; i
< b
.N
; i
++ {
704 Write(w
, BigEndian
, slice
)
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
)))
715 for i
:= 0; i
< b
.N
; i
++ {
717 Read(bsr
, BigEndian
, slice
)
721 func BenchmarkWriteSlice1000Uint8s(b
*testing
.B
) {
722 slice
:= make([]uint8, 1000)
723 buf
:= new(bytes
.Buffer
)
724 var w io
.Writer
= buf
727 for i
:= 0; i
< b
.N
; i
++ {
729 Write(w
, BigEndian
, slice
)