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

View as plain text