github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/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  type byteSliceReader struct {
   343  	remain []byte
   344  }
   345  
   346  func (br *byteSliceReader) Read(p []byte) (int, error) {
   347  	n := copy(p, br.remain)
   348  	br.remain = br.remain[n:]
   349  	return n, nil
   350  }
   351  
   352  func BenchmarkReadSlice1000Int32s(b *testing.B) {
   353  	bsr := &byteSliceReader{}
   354  	slice := make([]int32, 1000)
   355  	buf := make([]byte, len(slice)*4)
   356  	b.SetBytes(int64(len(buf)))
   357  	b.ResetTimer()
   358  	for i := 0; i < b.N; i++ {
   359  		bsr.remain = buf
   360  		Read(bsr, BigEndian, slice)
   361  	}
   362  }
   363  
   364  func BenchmarkReadStruct(b *testing.B) {
   365  	bsr := &byteSliceReader{}
   366  	var buf bytes.Buffer
   367  	Write(&buf, BigEndian, &s)
   368  	b.SetBytes(int64(dataSize(reflect.ValueOf(s))))
   369  	t := s
   370  	b.ResetTimer()
   371  	for i := 0; i < b.N; i++ {
   372  		bsr.remain = buf.Bytes()
   373  		Read(bsr, BigEndian, &t)
   374  	}
   375  	b.StopTimer()
   376  	if !reflect.DeepEqual(s, t) {
   377  		b.Fatal("no match")
   378  	}
   379  }
   380  
   381  func BenchmarkReadInts(b *testing.B) {
   382  	var ls Struct
   383  	bsr := &byteSliceReader{}
   384  	var r io.Reader = bsr
   385  	b.SetBytes(2 * (1 + 2 + 4 + 8))
   386  	b.ResetTimer()
   387  	for i := 0; i < b.N; i++ {
   388  		bsr.remain = big
   389  		Read(r, BigEndian, &ls.Int8)
   390  		Read(r, BigEndian, &ls.Int16)
   391  		Read(r, BigEndian, &ls.Int32)
   392  		Read(r, BigEndian, &ls.Int64)
   393  		Read(r, BigEndian, &ls.Uint8)
   394  		Read(r, BigEndian, &ls.Uint16)
   395  		Read(r, BigEndian, &ls.Uint32)
   396  		Read(r, BigEndian, &ls.Uint64)
   397  	}
   398  
   399  	want := s
   400  	want.Float32 = 0
   401  	want.Float64 = 0
   402  	want.Complex64 = 0
   403  	want.Complex128 = 0
   404  	for i := range want.Array {
   405  		want.Array[i] = 0
   406  	}
   407  	b.StopTimer()
   408  	if !reflect.DeepEqual(ls, want) {
   409  		panic("no match")
   410  	}
   411  }
   412  
   413  func BenchmarkWriteInts(b *testing.B) {
   414  	buf := new(bytes.Buffer)
   415  	var w io.Writer = buf
   416  	b.SetBytes(2 * (1 + 2 + 4 + 8))
   417  	b.ResetTimer()
   418  	for i := 0; i < b.N; i++ {
   419  		buf.Reset()
   420  		Write(w, BigEndian, s.Int8)
   421  		Write(w, BigEndian, s.Int16)
   422  		Write(w, BigEndian, s.Int32)
   423  		Write(w, BigEndian, s.Int64)
   424  		Write(w, BigEndian, s.Uint8)
   425  		Write(w, BigEndian, s.Uint16)
   426  		Write(w, BigEndian, s.Uint32)
   427  		Write(w, BigEndian, s.Uint64)
   428  	}
   429  	b.StopTimer()
   430  	if !bytes.Equal(buf.Bytes(), big[:30]) {
   431  		b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30])
   432  	}
   433  }
   434  
   435  func BenchmarkWriteSlice1000Int32s(b *testing.B) {
   436  	slice := make([]int32, 1000)
   437  	buf := new(bytes.Buffer)
   438  	var w io.Writer = buf
   439  	b.SetBytes(4 * 1000)
   440  	b.ResetTimer()
   441  	for i := 0; i < b.N; i++ {
   442  		buf.Reset()
   443  		Write(w, BigEndian, slice)
   444  	}
   445  	b.StopTimer()
   446  }