github.com/spotify/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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.NewBuffer(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.NewBuffer(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  type byteSliceReader struct {
   269  	remain []byte
   270  }
   271  
   272  func (br *byteSliceReader) Read(p []byte) (int, error) {
   273  	n := copy(p, br.remain)
   274  	br.remain = br.remain[n:]
   275  	return n, nil
   276  }
   277  
   278  func BenchmarkReadSlice1000Int32s(b *testing.B) {
   279  	bsr := &byteSliceReader{}
   280  	slice := make([]int32, 1000)
   281  	buf := make([]byte, len(slice)*4)
   282  	b.SetBytes(int64(len(buf)))
   283  	b.ResetTimer()
   284  	for i := 0; i < b.N; i++ {
   285  		bsr.remain = buf
   286  		Read(bsr, BigEndian, slice)
   287  	}
   288  }
   289  
   290  func BenchmarkReadStruct(b *testing.B) {
   291  	bsr := &byteSliceReader{}
   292  	var buf bytes.Buffer
   293  	Write(&buf, BigEndian, &s)
   294  	n, _ := dataSize(reflect.ValueOf(s))
   295  	b.SetBytes(int64(n))
   296  	t := s
   297  	b.ResetTimer()
   298  	for i := 0; i < b.N; i++ {
   299  		bsr.remain = buf.Bytes()
   300  		Read(bsr, BigEndian, &t)
   301  	}
   302  	b.StopTimer()
   303  	if !reflect.DeepEqual(s, t) {
   304  		b.Fatal("no match")
   305  	}
   306  }
   307  
   308  func BenchmarkReadInts(b *testing.B) {
   309  	var ls Struct
   310  	bsr := &byteSliceReader{}
   311  	var r io.Reader = bsr
   312  	b.SetBytes(2 * (1 + 2 + 4 + 8))
   313  	b.ResetTimer()
   314  	for i := 0; i < b.N; i++ {
   315  		bsr.remain = big
   316  		Read(r, BigEndian, &ls.Int8)
   317  		Read(r, BigEndian, &ls.Int16)
   318  		Read(r, BigEndian, &ls.Int32)
   319  		Read(r, BigEndian, &ls.Int64)
   320  		Read(r, BigEndian, &ls.Uint8)
   321  		Read(r, BigEndian, &ls.Uint16)
   322  		Read(r, BigEndian, &ls.Uint32)
   323  		Read(r, BigEndian, &ls.Uint64)
   324  	}
   325  
   326  	want := s
   327  	want.Float32 = 0
   328  	want.Float64 = 0
   329  	want.Complex64 = 0
   330  	want.Complex128 = 0
   331  	for i := range want.Array {
   332  		want.Array[i] = 0
   333  	}
   334  	b.StopTimer()
   335  	if !reflect.DeepEqual(ls, want) {
   336  		panic("no match")
   337  	}
   338  }
   339  
   340  func BenchmarkWriteInts(b *testing.B) {
   341  	buf := new(bytes.Buffer)
   342  	var w io.Writer = buf
   343  	b.SetBytes(2 * (1 + 2 + 4 + 8))
   344  	b.ResetTimer()
   345  	for i := 0; i < b.N; i++ {
   346  		buf.Reset()
   347  		Write(w, BigEndian, s.Int8)
   348  		Write(w, BigEndian, s.Int16)
   349  		Write(w, BigEndian, s.Int32)
   350  		Write(w, BigEndian, s.Int64)
   351  		Write(w, BigEndian, s.Uint8)
   352  		Write(w, BigEndian, s.Uint16)
   353  		Write(w, BigEndian, s.Uint32)
   354  		Write(w, BigEndian, s.Uint64)
   355  	}
   356  	b.StopTimer()
   357  	if !bytes.Equal(buf.Bytes(), big[:30]) {
   358  		b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30])
   359  	}
   360  }
   361  
   362  func BenchmarkWriteSlice1000Int32s(b *testing.B) {
   363  	slice := make([]int32, 1000)
   364  	buf := new(bytes.Buffer)
   365  	var w io.Writer = buf
   366  	b.SetBytes(4 * 1000)
   367  	b.ResetTimer()
   368  	for i := 0; i < b.N; i++ {
   369  		buf.Reset()
   370  		Write(w, BigEndian, slice)
   371  	}
   372  	b.StopTimer()
   373  }