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 BenchmarkWriteSlice1000Structs(b *testing.B) {
   635  	slice := make([]Struct, 1000)
   636  	buf := new(bytes.Buffer)
   637  	var w io.Writer = buf
   638  	b.SetBytes(int64(Size(slice)))
   639  	b.ResetTimer()
   640  	for i := 0; i < b.N; i++ {
   641  		buf.Reset()
   642  		Write(w, BigEndian, slice)
   643  	}
   644  	b.StopTimer()
   645  }
   646  
   647  func BenchmarkReadSlice1000Structs(b *testing.B) {
   648  	bsr := &byteSliceReader{}
   649  	slice := make([]Struct, 1000)
   650  	buf := make([]byte, Size(slice))
   651  	b.SetBytes(int64(len(buf)))
   652  	b.ResetTimer()
   653  	for i := 0; i < b.N; i++ {
   654  		bsr.remain = buf
   655  		Read(bsr, BigEndian, slice)
   656  	}
   657  }
   658  
   659  func BenchmarkReadInts(b *testing.B) {
   660  	var ls Struct
   661  	bsr := &byteSliceReader{}
   662  	var r io.Reader = bsr
   663  	b.SetBytes(2 * (1 + 2 + 4 + 8))
   664  	b.ResetTimer()
   665  	for i := 0; i < b.N; i++ {
   666  		bsr.remain = big
   667  		Read(r, BigEndian, &ls.Int8)
   668  		Read(r, BigEndian, &ls.Int16)
   669  		Read(r, BigEndian, &ls.Int32)
   670  		Read(r, BigEndian, &ls.Int64)
   671  		Read(r, BigEndian, &ls.Uint8)
   672  		Read(r, BigEndian, &ls.Uint16)
   673  		Read(r, BigEndian, &ls.Uint32)
   674  		Read(r, BigEndian, &ls.Uint64)
   675  	}
   676  	b.StopTimer()
   677  	want := s
   678  	want.Float32 = 0
   679  	want.Float64 = 0
   680  	want.Complex64 = 0
   681  	want.Complex128 = 0
   682  	want.Array = [4]uint8{0, 0, 0, 0}
   683  	want.Bool = false
   684  	want.BoolArray = [4]bool{false, false, false, false}
   685  	if b.N > 0 && !reflect.DeepEqual(ls, want) {
   686  		b.Fatalf("struct doesn't match:\ngot  %v;\nwant %v", ls, want)
   687  	}
   688  }
   689  
   690  func BenchmarkWriteInts(b *testing.B) {
   691  	buf := new(bytes.Buffer)
   692  	var w io.Writer = buf
   693  	b.SetBytes(2 * (1 + 2 + 4 + 8))
   694  	b.ResetTimer()
   695  	for i := 0; i < b.N; i++ {
   696  		buf.Reset()
   697  		Write(w, BigEndian, s.Int8)
   698  		Write(w, BigEndian, s.Int16)
   699  		Write(w, BigEndian, s.Int32)
   700  		Write(w, BigEndian, s.Int64)
   701  		Write(w, BigEndian, s.Uint8)
   702  		Write(w, BigEndian, s.Uint16)
   703  		Write(w, BigEndian, s.Uint32)
   704  		Write(w, BigEndian, s.Uint64)
   705  	}
   706  	b.StopTimer()
   707  	if b.N > 0 && !bytes.Equal(buf.Bytes(), big[:30]) {
   708  		b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30])
   709  	}
   710  }
   711  
   712  func BenchmarkWriteSlice1000Int32s(b *testing.B) {
   713  	slice := make([]int32, 1000)
   714  	buf := new(bytes.Buffer)
   715  	var w io.Writer = buf
   716  	b.SetBytes(4 * 1000)
   717  	b.ResetTimer()
   718  	for i := 0; i < b.N; i++ {
   719  		buf.Reset()
   720  		Write(w, BigEndian, slice)
   721  	}
   722  	b.StopTimer()
   723  }
   724  
   725  func BenchmarkPutUint16(b *testing.B) {
   726  	b.SetBytes(2)
   727  	for i := 0; i < b.N; i++ {
   728  		BigEndian.PutUint16(putbuf[:2], uint16(i))
   729  	}
   730  }
   731  
   732  func BenchmarkAppendUint16(b *testing.B) {
   733  	b.SetBytes(2)
   734  	for i := 0; i < b.N; i++ {
   735  		putbuf = BigEndian.AppendUint16(putbuf[:0], uint16(i))
   736  	}
   737  }
   738  
   739  func BenchmarkPutUint32(b *testing.B) {
   740  	b.SetBytes(4)
   741  	for i := 0; i < b.N; i++ {
   742  		BigEndian.PutUint32(putbuf[:4], uint32(i))
   743  	}
   744  }
   745  
   746  func BenchmarkAppendUint32(b *testing.B) {
   747  	b.SetBytes(4)
   748  	for i := 0; i < b.N; i++ {
   749  		putbuf = BigEndian.AppendUint32(putbuf[:0], uint32(i))
   750  	}
   751  }
   752  
   753  func BenchmarkPutUint64(b *testing.B) {
   754  	b.SetBytes(8)
   755  	for i := 0; i < b.N; i++ {
   756  		BigEndian.PutUint64(putbuf[:8], uint64(i))
   757  	}
   758  }
   759  
   760  func BenchmarkAppendUint64(b *testing.B) {
   761  	b.SetBytes(8)
   762  	for i := 0; i < b.N; i++ {
   763  		putbuf = BigEndian.AppendUint64(putbuf[:0], uint64(i))
   764  	}
   765  }
   766  
   767  func BenchmarkLittleEndianPutUint16(b *testing.B) {
   768  	b.SetBytes(2)
   769  	for i := 0; i < b.N; i++ {
   770  		LittleEndian.PutUint16(putbuf[:2], uint16(i))
   771  	}
   772  }
   773  
   774  func BenchmarkLittleEndianAppendUint16(b *testing.B) {
   775  	b.SetBytes(2)
   776  	for i := 0; i < b.N; i++ {
   777  		putbuf = LittleEndian.AppendUint16(putbuf[:0], uint16(i))
   778  	}
   779  }
   780  
   781  func BenchmarkLittleEndianPutUint32(b *testing.B) {
   782  	b.SetBytes(4)
   783  	for i := 0; i < b.N; i++ {
   784  		LittleEndian.PutUint32(putbuf[:4], uint32(i))
   785  	}
   786  }
   787  
   788  func BenchmarkLittleEndianAppendUint32(b *testing.B) {
   789  	b.SetBytes(4)
   790  	for i := 0; i < b.N; i++ {
   791  		putbuf = LittleEndian.AppendUint32(putbuf[:0], uint32(i))
   792  	}
   793  }
   794  
   795  func BenchmarkLittleEndianPutUint64(b *testing.B) {
   796  	b.SetBytes(8)
   797  	for i := 0; i < b.N; i++ {
   798  		LittleEndian.PutUint64(putbuf[:8], uint64(i))
   799  	}
   800  }
   801  
   802  func BenchmarkLittleEndianAppendUint64(b *testing.B) {
   803  	b.SetBytes(8)
   804  	for i := 0; i < b.N; i++ {
   805  		putbuf = LittleEndian.AppendUint64(putbuf[:0], uint64(i))
   806  	}
   807  }
   808  
   809  func BenchmarkReadFloats(b *testing.B) {
   810  	var ls Struct
   811  	bsr := &byteSliceReader{}
   812  	var r io.Reader = bsr
   813  	b.SetBytes(4 + 8)
   814  	b.ResetTimer()
   815  	for i := 0; i < b.N; i++ {
   816  		bsr.remain = big[30:]
   817  		Read(r, BigEndian, &ls.Float32)
   818  		Read(r, BigEndian, &ls.Float64)
   819  	}
   820  	b.StopTimer()
   821  	want := s
   822  	want.Int8 = 0
   823  	want.Int16 = 0
   824  	want.Int32 = 0
   825  	want.Int64 = 0
   826  	want.Uint8 = 0
   827  	want.Uint16 = 0
   828  	want.Uint32 = 0
   829  	want.Uint64 = 0
   830  	want.Complex64 = 0
   831  	want.Complex128 = 0
   832  	want.Array = [4]uint8{0, 0, 0, 0}
   833  	want.Bool = false
   834  	want.BoolArray = [4]bool{false, false, false, false}
   835  	if b.N > 0 && !reflect.DeepEqual(ls, want) {
   836  		b.Fatalf("struct doesn't match:\ngot  %v;\nwant %v", ls, want)
   837  	}
   838  }
   839  
   840  func BenchmarkWriteFloats(b *testing.B) {
   841  	buf := new(bytes.Buffer)
   842  	var w io.Writer = buf
   843  	b.SetBytes(4 + 8)
   844  	b.ResetTimer()
   845  	for i := 0; i < b.N; i++ {
   846  		buf.Reset()
   847  		Write(w, BigEndian, s.Float32)
   848  		Write(w, BigEndian, s.Float64)
   849  	}
   850  	b.StopTimer()
   851  	if b.N > 0 && !bytes.Equal(buf.Bytes(), big[30:30+4+8]) {
   852  		b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[30:30+4+8])
   853  	}
   854  }
   855  
   856  func BenchmarkReadSlice1000Float32s(b *testing.B) {
   857  	bsr := &byteSliceReader{}
   858  	slice := make([]float32, 1000)
   859  	buf := make([]byte, len(slice)*4)
   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 BenchmarkWriteSlice1000Float32s(b *testing.B) {
   869  	slice := make([]float32, 1000)
   870  	buf := new(bytes.Buffer)
   871  	var w io.Writer = buf
   872  	b.SetBytes(4 * 1000)
   873  	b.ResetTimer()
   874  	for i := 0; i < b.N; i++ {
   875  		buf.Reset()
   876  		Write(w, BigEndian, slice)
   877  	}
   878  	b.StopTimer()
   879  }
   880  
   881  func BenchmarkReadSlice1000Uint8s(b *testing.B) {
   882  	bsr := &byteSliceReader{}
   883  	slice := make([]uint8, 1000)
   884  	buf := make([]byte, len(slice))
   885  	b.SetBytes(int64(len(buf)))
   886  	b.ResetTimer()
   887  	for i := 0; i < b.N; i++ {
   888  		bsr.remain = buf
   889  		Read(bsr, BigEndian, slice)
   890  	}
   891  }
   892  
   893  func BenchmarkWriteSlice1000Uint8s(b *testing.B) {
   894  	slice := make([]uint8, 1000)
   895  	buf := new(bytes.Buffer)
   896  	var w io.Writer = buf
   897  	b.SetBytes(1000)
   898  	b.ResetTimer()
   899  	for i := 0; i < b.N; i++ {
   900  		buf.Reset()
   901  		Write(w, BigEndian, slice)
   902  	}
   903  }
   904  
   905  func TestNativeEndian(t *testing.T) {
   906  	const val = 0x12345678
   907  	i := uint32(val)
   908  	s := unsafe.Slice((*byte)(unsafe.Pointer(&i)), unsafe.Sizeof(i))
   909  	if v := NativeEndian.Uint32(s); v != val {
   910  		t.Errorf("NativeEndian.Uint32 returned %#x, expected %#x", v, val)
   911  	}
   912  }
   913  

View as plain text