1
2
3
4
5 package binary
6
7 import (
8 "bytes"
9 "fmt"
10 "internal/asan"
11 "io"
12 "math"
13 "reflect"
14 "strings"
15 "sync"
16 "testing"
17 "unsafe"
18 )
19
20 type Struct struct {
21 Int8 int8
22 Int16 int16
23 Int32 int32
24 Int64 int64
25 Uint8 uint8
26 Uint16 uint16
27 Uint32 uint32
28 Uint64 uint64
29 Float32 float32
30 Float64 float64
31 Complex64 complex64
32 Complex128 complex128
33 Array [4]uint8
34 Bool bool
35 BoolArray [4]bool
36 }
37
38 type T struct {
39 Int int
40 Uint uint
41 Uintptr uintptr
42 Array [4]int
43 }
44
45 var s = Struct{
46 0x01,
47 0x0203,
48 0x04050607,
49 0x08090a0b0c0d0e0f,
50 0x10,
51 0x1112,
52 0x13141516,
53 0x1718191a1b1c1d1e,
54
55 math.Float32frombits(0x1f202122),
56 math.Float64frombits(0x232425262728292a),
57 complex(
58 math.Float32frombits(0x2b2c2d2e),
59 math.Float32frombits(0x2f303132),
60 ),
61 complex(
62 math.Float64frombits(0x333435363738393a),
63 math.Float64frombits(0x3b3c3d3e3f404142),
64 ),
65
66 [4]uint8{0x43, 0x44, 0x45, 0x46},
67
68 true,
69 [4]bool{true, false, true, false},
70 }
71
72 var big = []byte{
73 1,
74 2, 3,
75 4, 5, 6, 7,
76 8, 9, 10, 11, 12, 13, 14, 15,
77 16,
78 17, 18,
79 19, 20, 21, 22,
80 23, 24, 25, 26, 27, 28, 29, 30,
81
82 31, 32, 33, 34,
83 35, 36, 37, 38, 39, 40, 41, 42,
84 43, 44, 45, 46, 47, 48, 49, 50,
85 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
86
87 67, 68, 69, 70,
88
89 1,
90 1, 0, 1, 0,
91 }
92
93 var little = []byte{
94 1,
95 3, 2,
96 7, 6, 5, 4,
97 15, 14, 13, 12, 11, 10, 9, 8,
98 16,
99 18, 17,
100 22, 21, 20, 19,
101 30, 29, 28, 27, 26, 25, 24, 23,
102
103 34, 33, 32, 31,
104 42, 41, 40, 39, 38, 37, 36, 35,
105 46, 45, 44, 43, 50, 49, 48, 47,
106 58, 57, 56, 55, 54, 53, 52, 51, 66, 65, 64, 63, 62, 61, 60, 59,
107
108 67, 68, 69, 70,
109
110 1,
111 1, 0, 1, 0,
112 }
113
114 var src = []byte{1, 2, 3, 4, 5, 6, 7, 8}
115 var res = []int32{0x01020304, 0x05060708}
116 var putbuf = []byte{0, 0, 0, 0, 0, 0, 0, 0}
117
118 func checkResult(t *testing.T, dir string, order ByteOrder, err error, have, want any) {
119 t.Helper()
120 if err != nil {
121 t.Errorf("%v %v: %v", dir, order, err)
122 return
123 }
124 if !reflect.DeepEqual(have, want) {
125 t.Errorf("%v %v:\n\thave %+v\n\twant %+v", dir, order, have, want)
126 }
127 }
128
129 var encoders = []struct {
130 name string
131 fn func(order ByteOrder, data any) ([]byte, error)
132 }{
133 {
134 "Write",
135 func(order ByteOrder, data any) ([]byte, error) {
136 buf := new(bytes.Buffer)
137 err := Write(buf, order, data)
138 return buf.Bytes(), err
139 },
140 },
141 {
142 "Encode",
143 func(order ByteOrder, data any) ([]byte, error) {
144 size := Size(data)
145
146 var buf []byte
147 if size > 0 {
148 buf = make([]byte, Size(data))
149 }
150
151 n, err := Encode(buf, order, data)
152 if err == nil && n != size {
153 return nil, fmt.Errorf("returned size %d instead of %d", n, size)
154 }
155 return buf, err
156 },
157 }, {
158 "Append",
159 func(order ByteOrder, data any) ([]byte, error) {
160 return Append(nil, order, data)
161 },
162 },
163 }
164
165 var decoders = []struct {
166 name string
167 fn func(order ByteOrder, data any, buf []byte) error
168 }{
169 {
170 "Read",
171 func(order ByteOrder, data any, buf []byte) error {
172 return Read(bytes.NewReader(buf), order, data)
173 },
174 },
175 {
176 "Decode",
177 func(order ByteOrder, data any, buf []byte) error {
178 n, err := Decode(buf, order, data)
179 if err == nil && n != Size(data) {
180 return fmt.Errorf("returned size %d instead of %d", n, Size(data))
181 }
182 return err
183 },
184 },
185 }
186
187 func testRead(t *testing.T, order ByteOrder, b []byte, s1 any) {
188 t.Helper()
189 for _, dec := range decoders {
190 t.Run(dec.name, func(t *testing.T) {
191 var s2 Struct
192 err := dec.fn(order, &s2, b)
193 checkResult(t, dec.name, order, err, s2, s1)
194 })
195 }
196 }
197
198 func testWrite(t *testing.T, order ByteOrder, b []byte, s1 any) {
199 t.Helper()
200 for _, enc := range encoders {
201 t.Run(enc.name, func(t *testing.T) {
202 buf, err := enc.fn(order, s1)
203 checkResult(t, enc.name, order, err, buf, b)
204 })
205 }
206 }
207
208 func TestLittleEndianRead(t *testing.T) { testRead(t, LittleEndian, little, s) }
209 func TestLittleEndianWrite(t *testing.T) { testWrite(t, LittleEndian, little, s) }
210 func TestLittleEndianPtrWrite(t *testing.T) { testWrite(t, LittleEndian, little, &s) }
211
212 func TestBigEndianRead(t *testing.T) { testRead(t, BigEndian, big, s) }
213 func TestBigEndianWrite(t *testing.T) { testWrite(t, BigEndian, big, s) }
214 func TestBigEndianPtrWrite(t *testing.T) { testWrite(t, BigEndian, big, &s) }
215
216 func TestReadSlice(t *testing.T) {
217 t.Run("Read", func(t *testing.T) {
218 slice := make([]int32, 2)
219 err := Read(bytes.NewReader(src), BigEndian, slice)
220 checkResult(t, "ReadSlice", BigEndian, err, slice, res)
221 })
222
223 t.Run("Decode", func(t *testing.T) {
224 slice := make([]int32, 2)
225 _, err := Decode(src, BigEndian, slice)
226 checkResult(t, "ReadSlice", BigEndian, err, slice, res)
227 })
228 }
229
230 func TestWriteSlice(t *testing.T) {
231 testWrite(t, BigEndian, src, res)
232 }
233
234 func TestReadBool(t *testing.T) {
235 for _, dec := range decoders {
236 t.Run(dec.name, func(t *testing.T) {
237 var res bool
238 var err error
239 err = dec.fn(BigEndian, &res, []byte{0})
240 checkResult(t, dec.name, BigEndian, err, res, false)
241 res = false
242 err = dec.fn(BigEndian, &res, []byte{1})
243 checkResult(t, dec.name, BigEndian, err, res, true)
244 res = false
245 err = dec.fn(BigEndian, &res, []byte{2})
246 checkResult(t, dec.name, BigEndian, err, res, true)
247 })
248 }
249
250 }
251
252 func TestReadBoolSlice(t *testing.T) {
253 for _, dec := range decoders {
254 t.Run(dec.name, func(t *testing.T) {
255 slice := make([]bool, 4)
256 err := dec.fn(BigEndian, slice, []byte{0, 1, 2, 255})
257 checkResult(t, dec.name, BigEndian, err, slice, []bool{false, true, true, true})
258 })
259 }
260 }
261
262
263 var intArrays = []any{
264 &[100]int8{},
265 &[100]int16{},
266 &[100]int32{},
267 &[100]int64{},
268 &[100]uint8{},
269 &[100]uint16{},
270 &[100]uint32{},
271 &[100]uint64{},
272 }
273
274 func TestSliceRoundTrip(t *testing.T) {
275 for _, enc := range encoders {
276 for _, dec := range decoders {
277 t.Run(fmt.Sprintf("%s,%s", enc.name, dec.name), func(t *testing.T) {
278 for _, array := range intArrays {
279 src := reflect.ValueOf(array).Elem()
280 t.Run(src.Index(0).Type().Name(), func(t *testing.T) {
281 unsigned := false
282 switch src.Index(0).Kind() {
283 case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
284 unsigned = true
285 }
286 for i := 0; i < src.Len(); i++ {
287 if unsigned {
288 src.Index(i).SetUint(uint64(i * 0x07654321))
289 } else {
290 src.Index(i).SetInt(int64(i * 0x07654321))
291 }
292 }
293 srcSlice := src.Slice(0, src.Len())
294 buf, err := enc.fn(BigEndian, srcSlice.Interface())
295 if err != nil {
296 t.Fatal(err)
297 }
298 dst := reflect.New(src.Type()).Elem()
299 dstSlice := dst.Slice(0, dst.Len())
300 err = dec.fn(BigEndian, dstSlice.Interface(), buf)
301 if err != nil {
302 t.Fatal(err)
303 }
304 if !reflect.DeepEqual(src.Interface(), dst.Interface()) {
305 t.Log(dst)
306 t.Fatal(src)
307 }
308 })
309 }
310 })
311 }
312 }
313 }
314
315 func TestWriteT(t *testing.T) {
316 for _, enc := range encoders {
317 t.Run(enc.name, func(t *testing.T) {
318 ts := T{}
319 if _, err := enc.fn(BigEndian, ts); err == nil {
320 t.Errorf("WriteT: have err == nil, want non-nil")
321 }
322
323 tv := reflect.Indirect(reflect.ValueOf(ts))
324 for i, n := 0, tv.NumField(); i < n; i++ {
325 typ := tv.Field(i).Type().String()
326 if typ == "[4]int" {
327 typ = "int"
328 }
329 if _, err := enc.fn(BigEndian, tv.Field(i).Interface()); err == nil {
330 t.Errorf("WriteT.%v: have err == nil, want non-nil", tv.Field(i).Type())
331 } else if !strings.Contains(err.Error(), typ) {
332 t.Errorf("WriteT: have err == %q, want it to mention %s", err, typ)
333 }
334 }
335 })
336 }
337 }
338
339 type BlankFields struct {
340 A uint32
341 _ int32
342 B float64
343 _ [4]int16
344 C byte
345 _ [7]byte
346 _ struct {
347 f [8]float32
348 }
349 }
350
351 type BlankFieldsProbe struct {
352 A uint32
353 P0 int32
354 B float64
355 P1 [4]int16
356 C byte
357 P2 [7]byte
358 P3 struct {
359 F [8]float32
360 }
361 }
362
363 func TestBlankFields(t *testing.T) {
364 for _, enc := range encoders {
365 t.Run(enc.name, func(t *testing.T) {
366 b1 := BlankFields{A: 1234567890, B: 2.718281828, C: 42}
367 buf, err := enc.fn(LittleEndian, &b1)
368 if err != nil {
369 t.Error(err)
370 }
371
372
373 var p BlankFieldsProbe
374 if err := Read(bytes.NewReader(buf), LittleEndian, &p); err != nil {
375 t.Error(err)
376 }
377
378
379 if p.P0 != 0 || p.P1[0] != 0 || p.P2[0] != 0 || p.P3.F[0] != 0 {
380 t.Errorf("non-zero values for originally blank fields: %#v", p)
381 }
382
383
384 buf, err = enc.fn(LittleEndian, &p)
385 if err != nil {
386 t.Error(err)
387 }
388
389
390 var b2 BlankFields
391 if err := Read(bytes.NewReader(buf), LittleEndian, &b2); err != nil {
392 t.Error(err)
393 }
394 if b1.A != b2.A || b1.B != b2.B || b1.C != b2.C {
395 t.Errorf("%#v != %#v", b1, b2)
396 }
397 })
398 }
399 }
400
401 func TestSizeStructCache(t *testing.T) {
402
403 structSize = sync.Map{}
404
405 count := func() int {
406 var i int
407 structSize.Range(func(_, _ any) bool {
408 i++
409 return true
410 })
411 return i
412 }
413
414 var total int
415 added := func() int {
416 delta := count() - total
417 total += delta
418 return delta
419 }
420
421 type foo struct {
422 A uint32
423 }
424
425 type bar struct {
426 A Struct
427 B foo
428 C Struct
429 }
430
431 testcases := []struct {
432 val any
433 want int
434 }{
435 {new(foo), 1},
436 {new([1]foo), 0},
437 {make([]foo, 1), 0},
438 {new(bar), 1},
439 {new(bar), 0},
440 {new(struct{ A Struct }), 1},
441 {new(struct{ A Struct }), 0},
442 {new([1]struct{ A Struct }), 0},
443 {make([]struct{ A Struct }, 1), 0},
444 }
445
446 for _, tc := range testcases {
447 if Size(tc.val) == -1 {
448 t.Fatalf("Can't get the size of %T", tc.val)
449 }
450
451 if n := added(); n != tc.want {
452 t.Errorf("Sizing %T added %d entries to the cache, want %d", tc.val, n, tc.want)
453 }
454 }
455 }
456
457 func TestSizeInvalid(t *testing.T) {
458 testcases := []any{
459 int(0),
460 new(int),
461 (*int)(nil),
462 [1]uint{},
463 new([1]uint),
464 (*[1]uint)(nil),
465 []int{},
466 []int(nil),
467 new([]int),
468 (*[]int)(nil),
469 (*int8)(nil),
470 (*uint8)(nil),
471 (*int16)(nil),
472 (*uint16)(nil),
473 (*int32)(nil),
474 (*uint32)(nil),
475 (*int64)(nil),
476 (*uint64)(nil),
477 (*float32)(nil),
478 (*float64)(nil),
479 (*complex64)(nil),
480 (*complex128)(nil),
481 }
482 for _, tc := range testcases {
483 if got := Size(tc); got != -1 {
484 t.Errorf("Size(%T) = %d, want -1", tc, got)
485 }
486 }
487 }
488
489
490
491
492
493 type Unexported struct {
494 a int32
495 }
496
497 func TestUnexportedRead(t *testing.T) {
498 var buf bytes.Buffer
499 u1 := Unexported{a: 1}
500 if err := Write(&buf, LittleEndian, &u1); err != nil {
501 t.Fatal(err)
502 }
503
504 for _, dec := range decoders {
505 t.Run(dec.name, func(t *testing.T) {
506 defer func() {
507 if recover() == nil {
508 t.Fatal("did not panic")
509 }
510 }()
511 var u2 Unexported
512 dec.fn(LittleEndian, &u2, buf.Bytes())
513 })
514 }
515
516 }
517
518 func TestReadErrorMsg(t *testing.T) {
519 for _, dec := range decoders {
520 t.Run(dec.name, func(t *testing.T) {
521 read := func(data any) {
522 err := dec.fn(LittleEndian, data, nil)
523 want := fmt.Sprintf("binary.%s: invalid type %s", dec.name, reflect.TypeOf(data).String())
524 if err == nil {
525 t.Errorf("%T: got no error; want %q", data, want)
526 return
527 }
528 if got := err.Error(); got != want {
529 t.Errorf("%T: got %q; want %q", data, got, want)
530 }
531 }
532 read(0)
533 s := new(struct{})
534 read(&s)
535 p := &s
536 read(&p)
537 })
538 }
539 }
540
541 func TestReadTruncated(t *testing.T) {
542 const data = "0123456789abcdef"
543
544 var b1 = make([]int32, 4)
545 var b2 struct {
546 A, B, C, D byte
547 E int32
548 F float64
549 }
550
551 for i := 0; i <= len(data); i++ {
552 var errWant error
553 switch i {
554 case 0:
555 errWant = io.EOF
556 case len(data):
557 errWant = nil
558 default:
559 errWant = io.ErrUnexpectedEOF
560 }
561
562 if err := Read(strings.NewReader(data[:i]), LittleEndian, &b1); err != errWant {
563 t.Errorf("Read(%d) with slice: got %v, want %v", i, err, errWant)
564 }
565 if err := Read(strings.NewReader(data[:i]), LittleEndian, &b2); err != errWant {
566 t.Errorf("Read(%d) with struct: got %v, want %v", i, err, errWant)
567 }
568 }
569 }
570
571 func testUint64SmallSliceLengthPanics() (panicked bool) {
572 defer func() {
573 panicked = recover() != nil
574 }()
575 b := [8]byte{1, 2, 3, 4, 5, 6, 7, 8}
576 LittleEndian.Uint64(b[:4])
577 return false
578 }
579
580 func testPutUint64SmallSliceLengthPanics() (panicked bool) {
581 defer func() {
582 panicked = recover() != nil
583 }()
584 b := [8]byte{}
585 LittleEndian.PutUint64(b[:4], 0x0102030405060708)
586 return false
587 }
588
589 func TestByteOrder(t *testing.T) {
590 type byteOrder interface {
591 ByteOrder
592 AppendByteOrder
593 }
594 buf := make([]byte, 8)
595 for _, order := range []byteOrder{LittleEndian, BigEndian} {
596 const offset = 3
597 for _, value := range []uint64{
598 0x0000000000000000,
599 0x0123456789abcdef,
600 0xfedcba9876543210,
601 0xffffffffffffffff,
602 0xaaaaaaaaaaaaaaaa,
603 math.Float64bits(math.Pi),
604 math.Float64bits(math.E),
605 } {
606 want16 := uint16(value)
607 order.PutUint16(buf[:2], want16)
608 if got := order.Uint16(buf[:2]); got != want16 {
609 t.Errorf("PutUint16: Uint16 = %v, want %v", got, want16)
610 }
611 buf = order.AppendUint16(buf[:offset], want16)
612 if got := order.Uint16(buf[offset:]); got != want16 {
613 t.Errorf("AppendUint16: Uint16 = %v, want %v", got, want16)
614 }
615 if len(buf) != offset+2 {
616 t.Errorf("AppendUint16: len(buf) = %d, want %d", len(buf), offset+2)
617 }
618
619 want32 := uint32(value)
620 order.PutUint32(buf[:4], want32)
621 if got := order.Uint32(buf[:4]); got != want32 {
622 t.Errorf("PutUint32: Uint32 = %v, want %v", got, want32)
623 }
624 buf = order.AppendUint32(buf[:offset], want32)
625 if got := order.Uint32(buf[offset:]); got != want32 {
626 t.Errorf("AppendUint32: Uint32 = %v, want %v", got, want32)
627 }
628 if len(buf) != offset+4 {
629 t.Errorf("AppendUint32: len(buf) = %d, want %d", len(buf), offset+4)
630 }
631
632 want64 := uint64(value)
633 order.PutUint64(buf[:8], want64)
634 if got := order.Uint64(buf[:8]); got != want64 {
635 t.Errorf("PutUint64: Uint64 = %v, want %v", got, want64)
636 }
637 buf = order.AppendUint64(buf[:offset], want64)
638 if got := order.Uint64(buf[offset:]); got != want64 {
639 t.Errorf("AppendUint64: Uint64 = %v, want %v", got, want64)
640 }
641 if len(buf) != offset+8 {
642 t.Errorf("AppendUint64: len(buf) = %d, want %d", len(buf), offset+8)
643 }
644 }
645 }
646 }
647
648 func TestEarlyBoundsChecks(t *testing.T) {
649 if testUint64SmallSliceLengthPanics() != true {
650 t.Errorf("binary.LittleEndian.Uint64 expected to panic for small slices, but didn't")
651 }
652 if testPutUint64SmallSliceLengthPanics() != true {
653 t.Errorf("binary.LittleEndian.PutUint64 expected to panic for small slices, but didn't")
654 }
655 }
656
657 func TestReadInvalidDestination(t *testing.T) {
658 testReadInvalidDestination(t, BigEndian)
659 testReadInvalidDestination(t, LittleEndian)
660 }
661
662 func testReadInvalidDestination(t *testing.T, order ByteOrder) {
663 destinations := []any{
664 int8(0),
665 int16(0),
666 int32(0),
667 int64(0),
668
669 uint8(0),
670 uint16(0),
671 uint32(0),
672 uint64(0),
673
674 bool(false),
675 }
676
677 for _, dst := range destinations {
678 err := Read(bytes.NewReader([]byte{1, 2, 3, 4, 5, 6, 7, 8}), order, dst)
679 want := fmt.Sprintf("binary.Read: invalid type %T", dst)
680 if err == nil || err.Error() != want {
681 t.Fatalf("for type %T: got %q; want %q", dst, err, want)
682 }
683 }
684 }
685
686 func TestNoFixedSize(t *testing.T) {
687 type Person struct {
688 Age int
689 Weight float64
690 Height float64
691 }
692
693 person := Person{
694 Age: 27,
695 Weight: 67.3,
696 Height: 177.8,
697 }
698
699 for _, enc := range encoders {
700 t.Run(enc.name, func(t *testing.T) {
701 _, err := enc.fn(LittleEndian, &person)
702 if err == nil {
703 t.Fatalf("binary.%s: unexpected success as size of type *binary.Person is not fixed", enc.name)
704 }
705 errs := fmt.Sprintf("binary.%s: some values are not fixed-sized in type *binary.Person", enc.name)
706 if err.Error() != errs {
707 t.Fatalf("got %q, want %q", err, errs)
708 }
709 })
710 }
711 }
712
713 func TestAppendAllocs(t *testing.T) {
714 if asan.Enabled {
715 t.Skip("test allocates more with -asan; see #70079")
716 }
717 buf := make([]byte, 0, Size(&s))
718 var err error
719 allocs := testing.AllocsPerRun(1, func() {
720 _, err = Append(buf, LittleEndian, &s)
721 })
722 if err != nil {
723 t.Fatal("Append failed:", err)
724 }
725 if allocs != 0 {
726 t.Fatalf("Append allocated %v times instead of not allocating at all", allocs)
727 }
728 }
729
730 var sizableTypes = []any{
731 bool(false),
732 int8(0),
733 int16(0),
734 int32(0),
735 int64(0),
736 uint8(0),
737 uint16(0),
738 uint32(0),
739 uint64(0),
740 float32(0),
741 float64(0),
742 complex64(0),
743 complex128(0),
744 Struct{},
745 &Struct{},
746 []Struct{},
747 ([]Struct)(nil),
748 [1]Struct{},
749 }
750
751 func TestSizeAllocs(t *testing.T) {
752 if asan.Enabled {
753 t.Skip("test allocates more with -asan; see #70079")
754 }
755 for _, data := range sizableTypes {
756 t.Run(fmt.Sprintf("%T", data), func(t *testing.T) {
757
758
759
760 allocs := testing.AllocsPerRun(10, func() {
761 _ = Size(data)
762 })
763 if allocs != 0 {
764 t.Fatalf("Expected no allocations, got %v", allocs)
765 }
766 })
767 }
768 }
769
770 type byteSliceReader struct {
771 remain []byte
772 }
773
774 func (br *byteSliceReader) Read(p []byte) (int, error) {
775 n := copy(p, br.remain)
776 br.remain = br.remain[n:]
777 return n, nil
778 }
779
780 func BenchmarkReadSlice1000Int32s(b *testing.B) {
781 bsr := &byteSliceReader{}
782 slice := make([]int32, 1000)
783 buf := make([]byte, len(slice)*4)
784 b.SetBytes(int64(len(buf)))
785 b.ResetTimer()
786 for i := 0; i < b.N; i++ {
787 bsr.remain = buf
788 Read(bsr, BigEndian, slice)
789 }
790 }
791
792 func BenchmarkReadStruct(b *testing.B) {
793 bsr := &byteSliceReader{}
794 var buf bytes.Buffer
795 Write(&buf, BigEndian, &s)
796 b.SetBytes(int64(dataSize(reflect.ValueOf(s))))
797 t := s
798 b.ResetTimer()
799 for i := 0; i < b.N; i++ {
800 bsr.remain = buf.Bytes()
801 Read(bsr, BigEndian, &t)
802 }
803 b.StopTimer()
804 if b.N > 0 && !reflect.DeepEqual(s, t) {
805 b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", t, s)
806 }
807 }
808
809 func BenchmarkWriteStruct(b *testing.B) {
810 b.SetBytes(int64(Size(&s)))
811 b.ResetTimer()
812 for i := 0; i < b.N; i++ {
813 Write(io.Discard, BigEndian, &s)
814 }
815 }
816
817 func BenchmarkAppendStruct(b *testing.B) {
818 buf := make([]byte, 0, Size(&s))
819 b.SetBytes(int64(cap(buf)))
820 b.ResetTimer()
821
822 for i := 0; i < b.N; i++ {
823 Encode(buf, BigEndian, &s)
824 }
825 }
826
827 func BenchmarkWriteSlice1000Structs(b *testing.B) {
828 slice := make([]Struct, 1000)
829 buf := new(bytes.Buffer)
830 var w io.Writer = buf
831 b.SetBytes(int64(Size(slice)))
832 b.ResetTimer()
833 for i := 0; i < b.N; i++ {
834 buf.Reset()
835 Write(w, BigEndian, slice)
836 }
837 b.StopTimer()
838 }
839
840 func BenchmarkAppendSlice1000Structs(b *testing.B) {
841 slice := make([]Struct, 1000)
842 buf := make([]byte, 0, Size(slice))
843 b.SetBytes(int64(cap(buf)))
844 b.ResetTimer()
845 for i := 0; i < b.N; i++ {
846 Append(buf, BigEndian, slice)
847 }
848 b.StopTimer()
849 }
850
851 func BenchmarkReadSlice1000Structs(b *testing.B) {
852 bsr := &byteSliceReader{}
853 slice := make([]Struct, 1000)
854 buf := make([]byte, Size(slice))
855 b.SetBytes(int64(len(buf)))
856 b.ResetTimer()
857 for i := 0; i < b.N; i++ {
858 bsr.remain = buf
859 Read(bsr, BigEndian, slice)
860 }
861 }
862
863 func BenchmarkReadInts(b *testing.B) {
864 var ls Struct
865 bsr := &byteSliceReader{}
866 var r io.Reader = bsr
867 b.SetBytes(2 * (1 + 2 + 4 + 8))
868 b.ResetTimer()
869 for i := 0; i < b.N; i++ {
870 bsr.remain = big
871 Read(r, BigEndian, &ls.Int8)
872 Read(r, BigEndian, &ls.Int16)
873 Read(r, BigEndian, &ls.Int32)
874 Read(r, BigEndian, &ls.Int64)
875 Read(r, BigEndian, &ls.Uint8)
876 Read(r, BigEndian, &ls.Uint16)
877 Read(r, BigEndian, &ls.Uint32)
878 Read(r, BigEndian, &ls.Uint64)
879 }
880 b.StopTimer()
881 want := s
882 want.Float32 = 0
883 want.Float64 = 0
884 want.Complex64 = 0
885 want.Complex128 = 0
886 want.Array = [4]uint8{0, 0, 0, 0}
887 want.Bool = false
888 want.BoolArray = [4]bool{false, false, false, false}
889 if b.N > 0 && !reflect.DeepEqual(ls, want) {
890 b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", ls, want)
891 }
892 }
893
894 func BenchmarkWriteInts(b *testing.B) {
895 buf := new(bytes.Buffer)
896 var w io.Writer = buf
897 b.SetBytes(2 * (1 + 2 + 4 + 8))
898 b.ResetTimer()
899 for i := 0; i < b.N; i++ {
900 buf.Reset()
901 Write(w, BigEndian, s.Int8)
902 Write(w, BigEndian, s.Int16)
903 Write(w, BigEndian, s.Int32)
904 Write(w, BigEndian, s.Int64)
905 Write(w, BigEndian, s.Uint8)
906 Write(w, BigEndian, s.Uint16)
907 Write(w, BigEndian, s.Uint32)
908 Write(w, BigEndian, s.Uint64)
909 }
910 b.StopTimer()
911 if b.N > 0 && !bytes.Equal(buf.Bytes(), big[:30]) {
912 b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30])
913 }
914 }
915
916 func BenchmarkAppendInts(b *testing.B) {
917 buf := make([]byte, 0, 256)
918 b.SetBytes(2 * (1 + 2 + 4 + 8))
919 b.ResetTimer()
920 for i := 0; i < b.N; i++ {
921 buf = buf[:0]
922 buf, _ = Append(buf, BigEndian, s.Int8)
923 buf, _ = Append(buf, BigEndian, s.Int16)
924 buf, _ = Append(buf, BigEndian, s.Int32)
925 buf, _ = Append(buf, BigEndian, s.Int64)
926 buf, _ = Append(buf, BigEndian, s.Uint8)
927 buf, _ = Append(buf, BigEndian, s.Uint16)
928 buf, _ = Append(buf, BigEndian, s.Uint32)
929 buf, _ = Append(buf, BigEndian, s.Uint64)
930 }
931 b.StopTimer()
932 if b.N > 0 && !bytes.Equal(buf, big[:30]) {
933 b.Fatalf("first half doesn't match: %x %x", buf, big[:30])
934 }
935 }
936
937 func BenchmarkWriteSlice1000Int32s(b *testing.B) {
938 slice := make([]int32, 1000)
939 buf := new(bytes.Buffer)
940 var w io.Writer = buf
941 b.SetBytes(4 * 1000)
942 b.ResetTimer()
943 for i := 0; i < b.N; i++ {
944 buf.Reset()
945 Write(w, BigEndian, slice)
946 }
947 b.StopTimer()
948 }
949
950 func BenchmarkAppendSlice1000Int32s(b *testing.B) {
951 slice := make([]int32, 1000)
952 buf := make([]byte, 0, Size(slice))
953 b.SetBytes(int64(cap(buf)))
954 b.ResetTimer()
955 for i := 0; i < b.N; i++ {
956 Append(buf, BigEndian, slice)
957 }
958 b.StopTimer()
959 }
960
961 func BenchmarkPutUint16(b *testing.B) {
962 b.SetBytes(2)
963 for i := 0; i < b.N; i++ {
964 BigEndian.PutUint16(putbuf[:2], uint16(i))
965 }
966 }
967
968 func BenchmarkAppendUint16(b *testing.B) {
969 b.SetBytes(2)
970 for i := 0; i < b.N; i++ {
971 putbuf = BigEndian.AppendUint16(putbuf[:0], uint16(i))
972 }
973 }
974
975 func BenchmarkPutUint32(b *testing.B) {
976 b.SetBytes(4)
977 for i := 0; i < b.N; i++ {
978 BigEndian.PutUint32(putbuf[:4], uint32(i))
979 }
980 }
981
982 func BenchmarkAppendUint32(b *testing.B) {
983 b.SetBytes(4)
984 for i := 0; i < b.N; i++ {
985 putbuf = BigEndian.AppendUint32(putbuf[:0], uint32(i))
986 }
987 }
988
989 func BenchmarkPutUint64(b *testing.B) {
990 b.SetBytes(8)
991 for i := 0; i < b.N; i++ {
992 BigEndian.PutUint64(putbuf[:8], uint64(i))
993 }
994 }
995
996 func BenchmarkAppendUint64(b *testing.B) {
997 b.SetBytes(8)
998 for i := 0; i < b.N; i++ {
999 putbuf = BigEndian.AppendUint64(putbuf[:0], uint64(i))
1000 }
1001 }
1002
1003 func BenchmarkLittleEndianPutUint16(b *testing.B) {
1004 b.SetBytes(2)
1005 for i := 0; i < b.N; i++ {
1006 LittleEndian.PutUint16(putbuf[:2], uint16(i))
1007 }
1008 }
1009
1010 func BenchmarkLittleEndianAppendUint16(b *testing.B) {
1011 b.SetBytes(2)
1012 for i := 0; i < b.N; i++ {
1013 putbuf = LittleEndian.AppendUint16(putbuf[:0], uint16(i))
1014 }
1015 }
1016
1017 func BenchmarkLittleEndianPutUint32(b *testing.B) {
1018 b.SetBytes(4)
1019 for i := 0; i < b.N; i++ {
1020 LittleEndian.PutUint32(putbuf[:4], uint32(i))
1021 }
1022 }
1023
1024 func BenchmarkLittleEndianAppendUint32(b *testing.B) {
1025 b.SetBytes(4)
1026 for i := 0; i < b.N; i++ {
1027 putbuf = LittleEndian.AppendUint32(putbuf[:0], uint32(i))
1028 }
1029 }
1030
1031 func BenchmarkLittleEndianPutUint64(b *testing.B) {
1032 b.SetBytes(8)
1033 for i := 0; i < b.N; i++ {
1034 LittleEndian.PutUint64(putbuf[:8], uint64(i))
1035 }
1036 }
1037
1038 func BenchmarkLittleEndianAppendUint64(b *testing.B) {
1039 b.SetBytes(8)
1040 for i := 0; i < b.N; i++ {
1041 putbuf = LittleEndian.AppendUint64(putbuf[:0], uint64(i))
1042 }
1043 }
1044
1045 func BenchmarkReadFloats(b *testing.B) {
1046 var ls Struct
1047 bsr := &byteSliceReader{}
1048 var r io.Reader = bsr
1049 b.SetBytes(4 + 8)
1050 b.ResetTimer()
1051 for i := 0; i < b.N; i++ {
1052 bsr.remain = big[30:]
1053 Read(r, BigEndian, &ls.Float32)
1054 Read(r, BigEndian, &ls.Float64)
1055 }
1056 b.StopTimer()
1057 want := s
1058 want.Int8 = 0
1059 want.Int16 = 0
1060 want.Int32 = 0
1061 want.Int64 = 0
1062 want.Uint8 = 0
1063 want.Uint16 = 0
1064 want.Uint32 = 0
1065 want.Uint64 = 0
1066 want.Complex64 = 0
1067 want.Complex128 = 0
1068 want.Array = [4]uint8{0, 0, 0, 0}
1069 want.Bool = false
1070 want.BoolArray = [4]bool{false, false, false, false}
1071 if b.N > 0 && !reflect.DeepEqual(ls, want) {
1072 b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", ls, want)
1073 }
1074 }
1075
1076 func BenchmarkWriteFloats(b *testing.B) {
1077 buf := new(bytes.Buffer)
1078 var w io.Writer = buf
1079 b.SetBytes(4 + 8)
1080 b.ResetTimer()
1081 for i := 0; i < b.N; i++ {
1082 buf.Reset()
1083 Write(w, BigEndian, s.Float32)
1084 Write(w, BigEndian, s.Float64)
1085 }
1086 b.StopTimer()
1087 if b.N > 0 && !bytes.Equal(buf.Bytes(), big[30:30+4+8]) {
1088 b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[30:30+4+8])
1089 }
1090 }
1091
1092 func BenchmarkReadSlice1000Float32s(b *testing.B) {
1093 bsr := &byteSliceReader{}
1094 slice := make([]float32, 1000)
1095 buf := make([]byte, len(slice)*4)
1096 b.SetBytes(int64(len(buf)))
1097 b.ResetTimer()
1098 for i := 0; i < b.N; i++ {
1099 bsr.remain = buf
1100 Read(bsr, BigEndian, slice)
1101 }
1102 }
1103
1104 func BenchmarkWriteSlice1000Float32s(b *testing.B) {
1105 slice := make([]float32, 1000)
1106 buf := new(bytes.Buffer)
1107 var w io.Writer = buf
1108 b.SetBytes(4 * 1000)
1109 b.ResetTimer()
1110 for i := 0; i < b.N; i++ {
1111 buf.Reset()
1112 Write(w, BigEndian, slice)
1113 }
1114 b.StopTimer()
1115 }
1116
1117 func BenchmarkReadSlice1000Uint8s(b *testing.B) {
1118 bsr := &byteSliceReader{}
1119 slice := make([]uint8, 1000)
1120 buf := make([]byte, len(slice))
1121 b.SetBytes(int64(len(buf)))
1122 b.ResetTimer()
1123 for i := 0; i < b.N; i++ {
1124 bsr.remain = buf
1125 Read(bsr, BigEndian, slice)
1126 }
1127 }
1128
1129 func BenchmarkWriteSlice1000Uint8s(b *testing.B) {
1130 slice := make([]uint8, 1000)
1131 buf := new(bytes.Buffer)
1132 var w io.Writer = buf
1133 b.SetBytes(1000)
1134 b.ResetTimer()
1135 for i := 0; i < b.N; i++ {
1136 buf.Reset()
1137 Write(w, BigEndian, slice)
1138 }
1139 }
1140
1141 func BenchmarkSize(b *testing.B) {
1142 for _, data := range sizableTypes {
1143 b.Run(fmt.Sprintf("%T", data), func(b *testing.B) {
1144 for range b.N {
1145 _ = Size(data)
1146 }
1147 })
1148 }
1149 }
1150
1151 func TestNativeEndian(t *testing.T) {
1152 const val = 0x12345678
1153 i := uint32(val)
1154 s := unsafe.Slice((*byte)(unsafe.Pointer(&i)), unsafe.Sizeof(i))
1155 if v := NativeEndian.Uint32(s); v != val {
1156 t.Errorf("NativeEndian.Uint32 returned %#x, expected %#x", v, val)
1157 }
1158 }
1159
View as plain text