github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/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  type byteSliceReader struct {
   313  	remain []byte
   314  }
   315  
   316  func (br *byteSliceReader) Read(p []byte) (int, error) {
   317  	n := copy(p, br.remain)
   318  	br.remain = br.remain[n:]
   319  	return n, nil
   320  }
   321  
   322  func BenchmarkReadSlice1000Int32s(b *testing.B) {
   323  	bsr := &byteSliceReader{}
   324  	slice := make([]int32, 1000)
   325  	buf := make([]byte, len(slice)*4)
   326  	b.SetBytes(int64(len(buf)))
   327  	b.ResetTimer()
   328  	for i := 0; i < b.N; i++ {
   329  		bsr.remain = buf
   330  		Read(bsr, BigEndian, slice)
   331  	}
   332  }
   333  
   334  func BenchmarkReadStruct(b *testing.B) {
   335  	bsr := &byteSliceReader{}
   336  	var buf bytes.Buffer
   337  	Write(&buf, BigEndian, &s)
   338  	b.SetBytes(int64(dataSize(reflect.ValueOf(s))))
   339  	t := s
   340  	b.ResetTimer()
   341  	for i := 0; i < b.N; i++ {
   342  		bsr.remain = buf.Bytes()
   343  		Read(bsr, BigEndian, &t)
   344  	}
   345  	b.StopTimer()
   346  	if !reflect.DeepEqual(s, t) {
   347  		b.Fatal("no match")
   348  	}
   349  }
   350  
   351  func BenchmarkReadInts(b *testing.B) {
   352  	var ls Struct
   353  	bsr := &byteSliceReader{}
   354  	var r io.Reader = bsr
   355  	b.SetBytes(2 * (1 + 2 + 4 + 8))
   356  	b.ResetTimer()
   357  	for i := 0; i < b.N; i++ {
   358  		bsr.remain = big
   359  		Read(r, BigEndian, &ls.Int8)
   360  		Read(r, BigEndian, &ls.Int16)
   361  		Read(r, BigEndian, &ls.Int32)
   362  		Read(r, BigEndian, &ls.Int64)
   363  		Read(r, BigEndian, &ls.Uint8)
   364  		Read(r, BigEndian, &ls.Uint16)
   365  		Read(r, BigEndian, &ls.Uint32)
   366  		Read(r, BigEndian, &ls.Uint64)
   367  	}
   368  
   369  	want := s
   370  	want.Float32 = 0
   371  	want.Float64 = 0
   372  	want.Complex64 = 0
   373  	want.Complex128 = 0
   374  	for i := range want.Array {
   375  		want.Array[i] = 0
   376  	}
   377  	b.StopTimer()
   378  	if !reflect.DeepEqual(ls, want) {
   379  		panic("no match")
   380  	}
   381  }
   382  
   383  func BenchmarkWriteInts(b *testing.B) {
   384  	buf := new(bytes.Buffer)
   385  	var w io.Writer = buf
   386  	b.SetBytes(2 * (1 + 2 + 4 + 8))
   387  	b.ResetTimer()
   388  	for i := 0; i < b.N; i++ {
   389  		buf.Reset()
   390  		Write(w, BigEndian, s.Int8)
   391  		Write(w, BigEndian, s.Int16)
   392  		Write(w, BigEndian, s.Int32)
   393  		Write(w, BigEndian, s.Int64)
   394  		Write(w, BigEndian, s.Uint8)
   395  		Write(w, BigEndian, s.Uint16)
   396  		Write(w, BigEndian, s.Uint32)
   397  		Write(w, BigEndian, s.Uint64)
   398  	}
   399  	b.StopTimer()
   400  	if !bytes.Equal(buf.Bytes(), big[:30]) {
   401  		b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30])
   402  	}
   403  }
   404  
   405  func BenchmarkWriteSlice1000Int32s(b *testing.B) {
   406  	slice := make([]int32, 1000)
   407  	buf := new(bytes.Buffer)
   408  	var w io.Writer = buf
   409  	b.SetBytes(4 * 1000)
   410  	b.ResetTimer()
   411  	for i := 0; i < b.N; i++ {
   412  		buf.Reset()
   413  		Write(w, BigEndian, slice)
   414  	}
   415  	b.StopTimer()
   416  }