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  	"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  // Addresses of arrays are easier to manipulate with reflection than are slices.
   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" // the problem is int, not the [4]
   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  			// zero values must have been written for blank fields
   373  			var p BlankFieldsProbe
   374  			if err := Read(bytes.NewReader(buf), LittleEndian, &p); err != nil {
   375  				t.Error(err)
   376  			}
   377  
   378  			// quick test: only check first value of slices
   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  			// write p and see if we can probe only some fields
   384  			buf, err = enc.fn(LittleEndian, &p)
   385  			if err != nil {
   386  				t.Error(err)
   387  			}
   388  
   389  			// read should ignore blank fields in b2
   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  	// Reset the cache, otherwise multiple test runs fail.
   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  // An attempt to read into a struct with an unexported field will
   490  // panic. This is probably not the best choice, but at this point
   491  // anything else would be an API change.
   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  			// Size uses a sync.Map behind the scenes. The slow lookup path of
   758  			// that does allocate, so we need a couple of runs here to be
   759  			// allocation free.
   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