Source file src/encoding/binary/binary_test.go

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

View as plain text