github.com/sbinet/go@v0.0.0-20160827155028-54d7de7dd62b/src/encoding/binary/binary_test.go (about)

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