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