...
Run Format

Source file src/encoding/binary/binary_test.go

Documentation: encoding/binary

     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  	"io"
    10  	"math"
    11  	"reflect"
    12  	"strings"
    13  	"testing"
    14  )
    15  
    16  type Struct struct {
    17  	Int8       int8
    18  	Int16      int16
    19  	Int32      int32
    20  	Int64      int64
    21  	Uint8      uint8
    22  	Uint16     uint16
    23  	Uint32     uint32
    24  	Uint64     uint64
    25  	Float32    float32
    26  	Float64    float64
    27  	Complex64  complex64
    28  	Complex128 complex128
    29  	Array      [4]uint8
    30  	Bool       bool
    31  	BoolArray  [4]bool
    32  }
    33  
    34  type T struct {
    35  	Int     int
    36  	Uint    uint
    37  	Uintptr uintptr
    38  	Array   [4]int
    39  }
    40  
    41  var s = Struct{
    42  	0x01,
    43  	0x0203,
    44  	0x04050607,
    45  	0x08090a0b0c0d0e0f,
    46  	0x10,
    47  	0x1112,
    48  	0x13141516,
    49  	0x1718191a1b1c1d1e,
    50  
    51  	math.Float32frombits(0x1f202122),
    52  	math.Float64frombits(0x232425262728292a),
    53  	complex(
    54  		math.Float32frombits(0x2b2c2d2e),
    55  		math.Float32frombits(0x2f303132),
    56  	),
    57  	complex(
    58  		math.Float64frombits(0x333435363738393a),
    59  		math.Float64frombits(0x3b3c3d3e3f404142),
    60  	),
    61  
    62  	[4]uint8{0x43, 0x44, 0x45, 0x46},
    63  
    64  	true,
    65  	[4]bool{true, false, true, false},
    66  }
    67  
    68  var big = []byte{
    69  	1,
    70  	2, 3,
    71  	4, 5, 6, 7,
    72  	8, 9, 10, 11, 12, 13, 14, 15,
    73  	16,
    74  	17, 18,
    75  	19, 20, 21, 22,
    76  	23, 24, 25, 26, 27, 28, 29, 30,
    77  
    78  	31, 32, 33, 34,
    79  	35, 36, 37, 38, 39, 40, 41, 42,
    80  	43, 44, 45, 46, 47, 48, 49, 50,
    81  	51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
    82  
    83  	67, 68, 69, 70,
    84  
    85  	1,
    86  	1, 0, 1, 0,
    87  }
    88  
    89  var little = []byte{
    90  	1,
    91  	3, 2,
    92  	7, 6, 5, 4,
    93  	15, 14, 13, 12, 11, 10, 9, 8,
    94  	16,
    95  	18, 17,
    96  	22, 21, 20, 19,
    97  	30, 29, 28, 27, 26, 25, 24, 23,
    98  
    99  	34, 33, 32, 31,
   100  	42, 41, 40, 39, 38, 37, 36, 35,
   101  	46, 45, 44, 43, 50, 49, 48, 47,
   102  	58, 57, 56, 55, 54, 53, 52, 51, 66, 65, 64, 63, 62, 61, 60, 59,
   103  
   104  	67, 68, 69, 70,
   105  
   106  	1,
   107  	1, 0, 1, 0,
   108  }
   109  
   110  var src = []byte{1, 2, 3, 4, 5, 6, 7, 8}
   111  var res = []int32{0x01020304, 0x05060708}
   112  var putbuf = []byte{0, 0, 0, 0, 0, 0, 0, 0}
   113  
   114  func checkResult(t *testing.T, dir string, order ByteOrder, err error, have, want interface{}) {
   115  	if err != nil {
   116  		t.Errorf("%v %v: %v", dir, order, err)
   117  		return
   118  	}
   119  	if !reflect.DeepEqual(have, want) {
   120  		t.Errorf("%v %v:\n\thave %+v\n\twant %+v", dir, order, have, want)
   121  	}
   122  }
   123  
   124  func testRead(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {
   125  	var s2 Struct
   126  	err := Read(bytes.NewReader(b), order, &s2)
   127  	checkResult(t, "Read", order, err, s2, s1)
   128  }
   129  
   130  func testWrite(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {
   131  	buf := new(bytes.Buffer)
   132  	err := Write(buf, order, s1)
   133  	checkResult(t, "Write", order, err, buf.Bytes(), b)
   134  }
   135  
   136  func TestLittleEndianRead(t *testing.T)     { testRead(t, LittleEndian, little, s) }
   137  func TestLittleEndianWrite(t *testing.T)    { testWrite(t, LittleEndian, little, s) }
   138  func TestLittleEndianPtrWrite(t *testing.T) { testWrite(t, LittleEndian, little, &s) }
   139  
   140  func TestBigEndianRead(t *testing.T)     { testRead(t, BigEndian, big, s) }
   141  func TestBigEndianWrite(t *testing.T)    { testWrite(t, BigEndian, big, s) }
   142  func TestBigEndianPtrWrite(t *testing.T) { testWrite(t, BigEndian, big, &s) }
   143  
   144  func TestReadSlice(t *testing.T) {
   145  	slice := make([]int32, 2)
   146  	err := Read(bytes.NewReader(src), BigEndian, slice)
   147  	checkResult(t, "ReadSlice", BigEndian, err, slice, res)
   148  }
   149  
   150  func TestWriteSlice(t *testing.T) {
   151  	buf := new(bytes.Buffer)
   152  	err := Write(buf, BigEndian, res)
   153  	checkResult(t, "WriteSlice", BigEndian, err, buf.Bytes(), src)
   154  }
   155  
   156  func TestReadBool(t *testing.T) {
   157  	var res bool
   158  	var err error
   159  	err = Read(bytes.NewReader([]byte{0}), BigEndian, &res)
   160  	checkResult(t, "ReadBool", BigEndian, err, res, false)
   161  	res = false
   162  	err = Read(bytes.NewReader([]byte{1}), BigEndian, &res)
   163  	checkResult(t, "ReadBool", BigEndian, err, res, true)
   164  	res = false
   165  	err = Read(bytes.NewReader([]byte{2}), BigEndian, &res)
   166  	checkResult(t, "ReadBool", BigEndian, err, res, true)
   167  }
   168  
   169  func TestReadBoolSlice(t *testing.T) {
   170  	slice := make([]bool, 4)
   171  	err := Read(bytes.NewReader([]byte{0, 1, 2, 255}), BigEndian, slice)
   172  	checkResult(t, "ReadBoolSlice", BigEndian, err, slice, []bool{false, true, true, true})
   173  }
   174  
   175  // Addresses of arrays are easier to manipulate with reflection than are slices.
   176  var intArrays = []interface{}{
   177  	&[100]int8{},
   178  	&[100]int16{},
   179  	&[100]int32{},
   180  	&[100]int64{},
   181  	&[100]uint8{},
   182  	&[100]uint16{},
   183  	&[100]uint32{},
   184  	&[100]uint64{},
   185  }
   186  
   187  func TestSliceRoundTrip(t *testing.T) {
   188  	buf := new(bytes.Buffer)
   189  	for _, array := range intArrays {
   190  		src := reflect.ValueOf(array).Elem()
   191  		unsigned := false
   192  		switch src.Index(0).Kind() {
   193  		case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   194  			unsigned = true
   195  		}
   196  		for i := 0; i < src.Len(); i++ {
   197  			if unsigned {
   198  				src.Index(i).SetUint(uint64(i * 0x07654321))
   199  			} else {
   200  				src.Index(i).SetInt(int64(i * 0x07654321))
   201  			}
   202  		}
   203  		buf.Reset()
   204  		srcSlice := src.Slice(0, src.Len())
   205  		err := Write(buf, BigEndian, srcSlice.Interface())
   206  		if err != nil {
   207  			t.Fatal(err)
   208  		}
   209  		dst := reflect.New(src.Type()).Elem()
   210  		dstSlice := dst.Slice(0, dst.Len())
   211  		err = Read(buf, BigEndian, dstSlice.Interface())
   212  		if err != nil {
   213  			t.Fatal(err)
   214  		}
   215  		if !reflect.DeepEqual(src.Interface(), dst.Interface()) {
   216  			t.Fatal(src)
   217  		}
   218  	}
   219  }
   220  
   221  func TestWriteT(t *testing.T) {
   222  	buf := new(bytes.Buffer)
   223  	ts := T{}
   224  	if err := Write(buf, BigEndian, ts); err == nil {
   225  		t.Errorf("WriteT: have err == nil, want non-nil")
   226  	}
   227  
   228  	tv := reflect.Indirect(reflect.ValueOf(ts))
   229  	for i, n := 0, tv.NumField(); i < n; i++ {
   230  		typ := tv.Field(i).Type().String()
   231  		if typ == "[4]int" {
   232  			typ = "int" // the problem is int, not the [4]
   233  		}
   234  		if err := Write(buf, BigEndian, tv.Field(i).Interface()); err == nil {
   235  			t.Errorf("WriteT.%v: have err == nil, want non-nil", tv.Field(i).Type())
   236  		} else if !strings.Contains(err.Error(), typ) {
   237  			t.Errorf("WriteT: have err == %q, want it to mention %s", err, typ)
   238  		}
   239  	}
   240  }
   241  
   242  type BlankFields struct {
   243  	A uint32
   244  	_ int32
   245  	B float64
   246  	_ [4]int16
   247  	C byte
   248  	_ [7]byte
   249  	_ struct {
   250  		f [8]float32
   251  	}
   252  }
   253  
   254  type BlankFieldsProbe struct {
   255  	A  uint32
   256  	P0 int32
   257  	B  float64
   258  	P1 [4]int16
   259  	C  byte
   260  	P2 [7]byte
   261  	P3 struct {
   262  		F [8]float32
   263  	}
   264  }
   265  
   266  func TestBlankFields(t *testing.T) {
   267  	buf := new(bytes.Buffer)
   268  	b1 := BlankFields{A: 1234567890, B: 2.718281828, C: 42}
   269  	if err := Write(buf, LittleEndian, &b1); err != nil {
   270  		t.Error(err)
   271  	}
   272  
   273  	// zero values must have been written for blank fields
   274  	var p BlankFieldsProbe
   275  	if err := Read(buf, LittleEndian, &p); err != nil {
   276  		t.Error(err)
   277  	}
   278  
   279  	// quick test: only check first value of slices
   280  	if p.P0 != 0 || p.P1[0] != 0 || p.P2[0] != 0 || p.P3.F[0] != 0 {
   281  		t.Errorf("non-zero values for originally blank fields: %#v", p)
   282  	}
   283  
   284  	// write p and see if we can probe only some fields
   285  	if err := Write(buf, LittleEndian, &p); err != nil {
   286  		t.Error(err)
   287  	}
   288  
   289  	// read should ignore blank fields in b2
   290  	var b2 BlankFields
   291  	if err := Read(buf, LittleEndian, &b2); err != nil {
   292  		t.Error(err)
   293  	}
   294  	if b1.A != b2.A || b1.B != b2.B || b1.C != b2.C {
   295  		t.Errorf("%#v != %#v", b1, b2)
   296  	}
   297  }
   298  
   299  // An attempt to read into a struct with an unexported field will
   300  // panic. This is probably not the best choice, but at this point
   301  // anything else would be an API change.
   302  
   303  type Unexported struct {
   304  	a int32
   305  }
   306  
   307  func TestUnexportedRead(t *testing.T) {
   308  	var buf bytes.Buffer
   309  	u1 := Unexported{a: 1}
   310  	if err := Write(&buf, LittleEndian, &u1); err != nil {
   311  		t.Fatal(err)
   312  	}
   313  
   314  	defer func() {
   315  		if recover() == nil {
   316  			t.Fatal("did not panic")
   317  		}
   318  	}()
   319  	var u2 Unexported
   320  	Read(&buf, LittleEndian, &u2)
   321  }
   322  
   323  func TestReadErrorMsg(t *testing.T) {
   324  	var buf bytes.Buffer
   325  	read := func(data interface{}) {
   326  		err := Read(&buf, LittleEndian, data)
   327  		want := "binary.Read: invalid type " + reflect.TypeOf(data).String()
   328  		if err == nil {
   329  			t.Errorf("%T: got no error; want %q", data, want)
   330  			return
   331  		}
   332  		if got := err.Error(); got != want {
   333  			t.Errorf("%T: got %q; want %q", data, got, want)
   334  		}
   335  	}
   336  	read(0)
   337  	s := new(struct{})
   338  	read(&s)
   339  	p := &s
   340  	read(&p)
   341  }
   342  
   343  func TestReadTruncated(t *testing.T) {
   344  	const data = "0123456789abcdef"
   345  
   346  	var b1 = make([]int32, 4)
   347  	var b2 struct {
   348  		A, B, C, D byte
   349  		E          int32
   350  		F          float64
   351  	}
   352  
   353  	for i := 0; i <= len(data); i++ {
   354  		var errWant error
   355  		switch i {
   356  		case 0:
   357  			errWant = io.EOF
   358  		case len(data):
   359  			errWant = nil
   360  		default:
   361  			errWant = io.ErrUnexpectedEOF
   362  		}
   363  
   364  		if err := Read(strings.NewReader(data[:i]), LittleEndian, &b1); err != errWant {
   365  			t.Errorf("Read(%d) with slice: got %v, want %v", i, err, errWant)
   366  		}
   367  		if err := Read(strings.NewReader(data[:i]), LittleEndian, &b2); err != errWant {
   368  			t.Errorf("Read(%d) with struct: got %v, want %v", i, err, errWant)
   369  		}
   370  	}
   371  }
   372  
   373  func testUint64SmallSliceLengthPanics() (panicked bool) {
   374  	defer func() {
   375  		panicked = recover() != nil
   376  	}()
   377  	b := [8]byte{1, 2, 3, 4, 5, 6, 7, 8}
   378  	LittleEndian.Uint64(b[:4])
   379  	return false
   380  }
   381  
   382  func testPutUint64SmallSliceLengthPanics() (panicked bool) {
   383  	defer func() {
   384  		panicked = recover() != nil
   385  	}()
   386  	b := [8]byte{}
   387  	LittleEndian.PutUint64(b[:4], 0x0102030405060708)
   388  	return false
   389  }
   390  
   391  func TestEarlyBoundsChecks(t *testing.T) {
   392  	if testUint64SmallSliceLengthPanics() != true {
   393  		t.Errorf("binary.LittleEndian.Uint64 expected to panic for small slices, but didn't")
   394  	}
   395  	if testPutUint64SmallSliceLengthPanics() != true {
   396  		t.Errorf("binary.LittleEndian.PutUint64 expected to panic for small slices, but didn't")
   397  	}
   398  }
   399  
   400  type byteSliceReader struct {
   401  	remain []byte
   402  }
   403  
   404  func (br *byteSliceReader) Read(p []byte) (int, error) {
   405  	n := copy(p, br.remain)
   406  	br.remain = br.remain[n:]
   407  	return n, nil
   408  }
   409  
   410  func BenchmarkReadSlice1000Int32s(b *testing.B) {
   411  	bsr := &byteSliceReader{}
   412  	slice := make([]int32, 1000)
   413  	buf := make([]byte, len(slice)*4)
   414  	b.SetBytes(int64(len(buf)))
   415  	b.ResetTimer()
   416  	for i := 0; i < b.N; i++ {
   417  		bsr.remain = buf
   418  		Read(bsr, BigEndian, slice)
   419  	}
   420  }
   421  
   422  func BenchmarkReadStruct(b *testing.B) {
   423  	bsr := &byteSliceReader{}
   424  	var buf bytes.Buffer
   425  	Write(&buf, BigEndian, &s)
   426  	b.SetBytes(int64(dataSize(reflect.ValueOf(s))))
   427  	t := s
   428  	b.ResetTimer()
   429  	for i := 0; i < b.N; i++ {
   430  		bsr.remain = buf.Bytes()
   431  		Read(bsr, BigEndian, &t)
   432  	}
   433  	b.StopTimer()
   434  	if b.N > 0 && !reflect.DeepEqual(s, t) {
   435  		b.Fatalf("struct doesn't match:\ngot  %v;\nwant %v", t, s)
   436  	}
   437  }
   438  
   439  func BenchmarkReadInts(b *testing.B) {
   440  	var ls Struct
   441  	bsr := &byteSliceReader{}
   442  	var r io.Reader = bsr
   443  	b.SetBytes(2 * (1 + 2 + 4 + 8))
   444  	b.ResetTimer()
   445  	for i := 0; i < b.N; i++ {
   446  		bsr.remain = big
   447  		Read(r, BigEndian, &ls.Int8)
   448  		Read(r, BigEndian, &ls.Int16)
   449  		Read(r, BigEndian, &ls.Int32)
   450  		Read(r, BigEndian, &ls.Int64)
   451  		Read(r, BigEndian, &ls.Uint8)
   452  		Read(r, BigEndian, &ls.Uint16)
   453  		Read(r, BigEndian, &ls.Uint32)
   454  		Read(r, BigEndian, &ls.Uint64)
   455  	}
   456  	b.StopTimer()
   457  	want := s
   458  	want.Float32 = 0
   459  	want.Float64 = 0
   460  	want.Complex64 = 0
   461  	want.Complex128 = 0
   462  	want.Array = [4]uint8{0, 0, 0, 0}
   463  	want.Bool = false
   464  	want.BoolArray = [4]bool{false, false, false, false}
   465  	if b.N > 0 && !reflect.DeepEqual(ls, want) {
   466  		b.Fatalf("struct doesn't match:\ngot  %v;\nwant %v", ls, want)
   467  	}
   468  }
   469  
   470  func BenchmarkWriteInts(b *testing.B) {
   471  	buf := new(bytes.Buffer)
   472  	var w io.Writer = buf
   473  	b.SetBytes(2 * (1 + 2 + 4 + 8))
   474  	b.ResetTimer()
   475  	for i := 0; i < b.N; i++ {
   476  		buf.Reset()
   477  		Write(w, BigEndian, s.Int8)
   478  		Write(w, BigEndian, s.Int16)
   479  		Write(w, BigEndian, s.Int32)
   480  		Write(w, BigEndian, s.Int64)
   481  		Write(w, BigEndian, s.Uint8)
   482  		Write(w, BigEndian, s.Uint16)
   483  		Write(w, BigEndian, s.Uint32)
   484  		Write(w, BigEndian, s.Uint64)
   485  	}
   486  	b.StopTimer()
   487  	if b.N > 0 && !bytes.Equal(buf.Bytes(), big[:30]) {
   488  		b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30])
   489  	}
   490  }
   491  
   492  func BenchmarkWriteSlice1000Int32s(b *testing.B) {
   493  	slice := make([]int32, 1000)
   494  	buf := new(bytes.Buffer)
   495  	var w io.Writer = buf
   496  	b.SetBytes(4 * 1000)
   497  	b.ResetTimer()
   498  	for i := 0; i < b.N; i++ {
   499  		buf.Reset()
   500  		Write(w, BigEndian, slice)
   501  	}
   502  	b.StopTimer()
   503  }
   504  
   505  func BenchmarkPutUint16(b *testing.B) {
   506  	b.SetBytes(2)
   507  	for i := 0; i < b.N; i++ {
   508  		BigEndian.PutUint16(putbuf[:], uint16(i))
   509  	}
   510  }
   511  
   512  func BenchmarkPutUint32(b *testing.B) {
   513  	b.SetBytes(4)
   514  	for i := 0; i < b.N; i++ {
   515  		BigEndian.PutUint32(putbuf[:], uint32(i))
   516  	}
   517  }
   518  
   519  func BenchmarkPutUint64(b *testing.B) {
   520  	b.SetBytes(8)
   521  	for i := 0; i < b.N; i++ {
   522  		BigEndian.PutUint64(putbuf[:], uint64(i))
   523  	}
   524  }
   525  func BenchmarkLittleEndianPutUint16(b *testing.B) {
   526  	b.SetBytes(2)
   527  	for i := 0; i < b.N; i++ {
   528  		LittleEndian.PutUint16(putbuf[:], uint16(i))
   529  	}
   530  }
   531  
   532  func BenchmarkLittleEndianPutUint32(b *testing.B) {
   533  	b.SetBytes(4)
   534  	for i := 0; i < b.N; i++ {
   535  		LittleEndian.PutUint32(putbuf[:], uint32(i))
   536  	}
   537  }
   538  
   539  func BenchmarkLittleEndianPutUint64(b *testing.B) {
   540  	b.SetBytes(8)
   541  	for i := 0; i < b.N; i++ {
   542  		LittleEndian.PutUint64(putbuf[:], uint64(i))
   543  	}
   544  }
   545  

View as plain text