446 lines · 9.8 KB · Go
RawDownload
// Copyright 2009 The Go Authors.  All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file. package binary import (	"bytes"	"io"	"math"	"reflect"	"strings"	"testing") type Struct struct {	Int8       int8	Int16      int16	Int32      int32	Int64      int64	Uint8      uint8	Uint16     uint16	Uint32     uint32	Uint64     uint64	Float32    float32	Float64    float64	Complex64  complex64	Complex128 complex128	Array      [4]uint8} type T struct {	Int     int	Uint    uint	Uintptr uintptr	Array   [4]int} var s = Struct{	0x01,	0x0203,	0x04050607,	0x08090a0b0c0d0e0f,	0x10,	0x1112,	0x13141516,	0x1718191a1b1c1d1e, 	math.Float32frombits(0x1f202122),	math.Float64frombits(0x232425262728292a),	complex(		math.Float32frombits(0x2b2c2d2e),		math.Float32frombits(0x2f303132),	),	complex(		math.Float64frombits(0x333435363738393a),		math.Float64frombits(0x3b3c3d3e3f404142),	), 	[4]uint8{0x43, 0x44, 0x45, 0x46},} var big = []byte{	1,	2, 3,	4, 5, 6, 7,	8, 9, 10, 11, 12, 13, 14, 15,	16,	17, 18,	19, 20, 21, 22,	23, 24, 25, 26, 27, 28, 29, 30, 	31, 32, 33, 34,	35, 36, 37, 38, 39, 40, 41, 42,	43, 44, 45, 46, 47, 48, 49, 50,	51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 	67, 68, 69, 70,} var little = []byte{	1,	3, 2,	7, 6, 5, 4,	15, 14, 13, 12, 11, 10, 9, 8,	16,	18, 17,	22, 21, 20, 19,	30, 29, 28, 27, 26, 25, 24, 23, 	34, 33, 32, 31,	42, 41, 40, 39, 38, 37, 36, 35,	46, 45, 44, 43, 50, 49, 48, 47,	58, 57, 56, 55, 54, 53, 52, 51, 66, 65, 64, 63, 62, 61, 60, 59, 	67, 68, 69, 70,} var src = []byte{1, 2, 3, 4, 5, 6, 7, 8}var res = []int32{0x01020304, 0x05060708} func checkResult(t *testing.T, dir string, order ByteOrder, err error, have, want interface{}) {	if err != nil {		t.Errorf("%v %v: %v", dir, order, err)		return	}	if !reflect.DeepEqual(have, want) {		t.Errorf("%v %v:\n\thave %+v\n\twant %+v", dir, order, have, want)	}} func testRead(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {	var s2 Struct	err := Read(bytes.NewReader(b), order, &s2)	checkResult(t, "Read", order, err, s2, s1)} func testWrite(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {	buf := new(bytes.Buffer)	err := Write(buf, order, s1)	checkResult(t, "Write", order, err, buf.Bytes(), b)} func TestLittleEndianRead(t *testing.T)     { testRead(t, LittleEndian, little, s) }func TestLittleEndianWrite(t *testing.T)    { testWrite(t, LittleEndian, little, s) }func TestLittleEndianPtrWrite(t *testing.T) { testWrite(t, LittleEndian, little, &s) } func TestBigEndianRead(t *testing.T)     { testRead(t, BigEndian, big, s) }func TestBigEndianWrite(t *testing.T)    { testWrite(t, BigEndian, big, s) }func TestBigEndianPtrWrite(t *testing.T) { testWrite(t, BigEndian, big, &s) } func TestReadSlice(t *testing.T) {	slice := make([]int32, 2)	err := Read(bytes.NewReader(src), BigEndian, slice)	checkResult(t, "ReadSlice", BigEndian, err, slice, res)} func TestWriteSlice(t *testing.T) {	buf := new(bytes.Buffer)	err := Write(buf, BigEndian, res)	checkResult(t, "WriteSlice", BigEndian, err, buf.Bytes(), src)} // Addresses of arrays are easier to manipulate with reflection than are slices.var intArrays = []interface{}{	&[100]int8{},	&[100]int16{},	&[100]int32{},	&[100]int64{},	&[100]uint8{},	&[100]uint16{},	&[100]uint32{},	&[100]uint64{},} func TestSliceRoundTrip(t *testing.T) {	buf := new(bytes.Buffer)	for _, array := range intArrays {		src := reflect.ValueOf(array).Elem()		unsigned := false		switch src.Index(0).Kind() {		case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:			unsigned = true		}		for i := 0; i < src.Len(); i++ {			if unsigned {				src.Index(i).SetUint(uint64(i * 0x07654321))			} else {				src.Index(i).SetInt(int64(i * 0x07654321))			}		}		buf.Reset()		srcSlice := src.Slice(0, src.Len())		err := Write(buf, BigEndian, srcSlice.Interface())		if err != nil {			t.Fatal(err)		}		dst := reflect.New(src.Type()).Elem()		dstSlice := dst.Slice(0, dst.Len())		err = Read(buf, BigEndian, dstSlice.Interface())		if err != nil {			t.Fatal(err)		}		if !reflect.DeepEqual(src.Interface(), dst.Interface()) {			t.Fatal(src)		}	}} func TestWriteT(t *testing.T) {	buf := new(bytes.Buffer)	ts := T{}	if err := Write(buf, BigEndian, ts); err == nil {		t.Errorf("WriteT: have err == nil, want non-nil")	} 	tv := reflect.Indirect(reflect.ValueOf(ts))	for i, n := 0, tv.NumField(); i < n; i++ {		typ := tv.Field(i).Type().String()		if typ == "[4]int" {			typ = "int" // the problem is int, not the [4]		}		if err := Write(buf, BigEndian, tv.Field(i).Interface()); err == nil {			t.Errorf("WriteT.%v: have err == nil, want non-nil", tv.Field(i).Type())		} else if !strings.Contains(err.Error(), typ) {			t.Errorf("WriteT: have err == %q, want it to mention %s", err, typ)		}	}} type BlankFields struct {	A uint32	_ int32	B float64	_ [4]int16	C byte	_ [7]byte	_ struct {		f [8]float32	}} type BlankFieldsProbe struct {	A  uint32	P0 int32	B  float64	P1 [4]int16	C  byte	P2 [7]byte	P3 struct {		F [8]float32	}} func TestBlankFields(t *testing.T) {	buf := new(bytes.Buffer)	b1 := BlankFields{A: 1234567890, B: 2.718281828, C: 42}	if err := Write(buf, LittleEndian, &b1); err != nil {		t.Error(err)	} 	// zero values must have been written for blank fields	var p BlankFieldsProbe	if err := Read(buf, LittleEndian, &p); err != nil {		t.Error(err)	} 	// quick test: only check first value of slices	if p.P0 != 0 || p.P1[0] != 0 || p.P2[0] != 0 || p.P3.F[0] != 0 {		t.Errorf("non-zero values for originally blank fields: %#v", p)	} 	// write p and see if we can probe only some fields	if err := Write(buf, LittleEndian, &p); err != nil {		t.Error(err)	} 	// read should ignore blank fields in b2	var b2 BlankFields	if err := Read(buf, LittleEndian, &b2); err != nil {		t.Error(err)	}	if b1.A != b2.A || b1.B != b2.B || b1.C != b2.C {		t.Errorf("%#v != %#v", b1, b2)	}} // An attempt to read into a struct with an unexported field will// panic.  This is probably not the best choice, but at this point// anything else would be an API change. type Unexported struct {	a int32} func TestUnexportedRead(t *testing.T) {	var buf bytes.Buffer	u1 := Unexported{a: 1}	if err := Write(&buf, LittleEndian, &u1); err != nil {		t.Fatal(err)	} 	defer func() {		if recover() == nil {			t.Fatal("did not panic")		}	}()	var u2 Unexported	Read(&buf, LittleEndian, &u2)} func TestReadErrorMsg(t *testing.T) {	var buf bytes.Buffer	read := func(data interface{}) {		err := Read(&buf, LittleEndian, data)		want := "binary.Read: invalid type " + reflect.TypeOf(data).String()		if err == nil {			t.Errorf("%T: got no error; want %q", data, want)			return		}		if got := err.Error(); got != want {			t.Errorf("%T: got %q; want %q", data, got, want)		}	}	read(0)	s := new(struct{})	read(&s)	p := &s	read(&p)} func TestReadTruncated(t *testing.T) {	const data = "0123456789abcdef" 	var b1 = make([]int32, 4)	var b2 struct {		A, B, C, D byte		E          int32		F          float64	} 	for i := 0; i <= len(data); i++ {		var errWant error		switch i {		case 0:			errWant = io.EOF		case len(data):			errWant = nil		default:			errWant = io.ErrUnexpectedEOF		} 		if err := Read(strings.NewReader(data[:i]), LittleEndian, &b1); err != errWant {			t.Errorf("Read(%d) with slice: got %v, want %v", i, err, errWant)		}		if err := Read(strings.NewReader(data[:i]), LittleEndian, &b2); err != errWant {			t.Errorf("Read(%d) with struct: got %v, want %v", i, err, errWant)		}	}} type byteSliceReader struct {	remain []byte} func (br *byteSliceReader) Read(p []byte) (int, error) {	n := copy(p, br.remain)	br.remain = br.remain[n:]	return n, nil} func BenchmarkReadSlice1000Int32s(b *testing.B) {	bsr := &byteSliceReader{}	slice := make([]int32, 1000)	buf := make([]byte, len(slice)*4)	b.SetBytes(int64(len(buf)))	b.ResetTimer()	for i := 0; i < b.N; i++ {		bsr.remain = buf		Read(bsr, BigEndian, slice)	}} func BenchmarkReadStruct(b *testing.B) {	bsr := &byteSliceReader{}	var buf bytes.Buffer	Write(&buf, BigEndian, &s)	b.SetBytes(int64(dataSize(reflect.ValueOf(s))))	t := s	b.ResetTimer()	for i := 0; i < b.N; i++ {		bsr.remain = buf.Bytes()		Read(bsr, BigEndian, &t)	}	b.StopTimer()	if !reflect.DeepEqual(s, t) {		b.Fatal("no match")	}} func BenchmarkReadInts(b *testing.B) {	var ls Struct	bsr := &byteSliceReader{}	var r io.Reader = bsr	b.SetBytes(2 * (1 + 2 + 4 + 8))	b.ResetTimer()	for i := 0; i < b.N; i++ {		bsr.remain = big		Read(r, BigEndian, &ls.Int8)		Read(r, BigEndian, &ls.Int16)		Read(r, BigEndian, &ls.Int32)		Read(r, BigEndian, &ls.Int64)		Read(r, BigEndian, &ls.Uint8)		Read(r, BigEndian, &ls.Uint16)		Read(r, BigEndian, &ls.Uint32)		Read(r, BigEndian, &ls.Uint64)	} 	want := s	want.Float32 = 0	want.Float64 = 0	want.Complex64 = 0	want.Complex128 = 0	for i := range want.Array {		want.Array[i] = 0	}	b.StopTimer()	if !reflect.DeepEqual(ls, want) {		panic("no match")	}} func BenchmarkWriteInts(b *testing.B) {	buf := new(bytes.Buffer)	var w io.Writer = buf	b.SetBytes(2 * (1 + 2 + 4 + 8))	b.ResetTimer()	for i := 0; i < b.N; i++ {		buf.Reset()		Write(w, BigEndian, s.Int8)		Write(w, BigEndian, s.Int16)		Write(w, BigEndian, s.Int32)		Write(w, BigEndian, s.Int64)		Write(w, BigEndian, s.Uint8)		Write(w, BigEndian, s.Uint16)		Write(w, BigEndian, s.Uint32)		Write(w, BigEndian, s.Uint64)	}	b.StopTimer()	if !bytes.Equal(buf.Bytes(), big[:30]) {		b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30])	}} func BenchmarkWriteSlice1000Int32s(b *testing.B) {	slice := make([]int32, 1000)	buf := new(bytes.Buffer)	var w io.Writer = buf	b.SetBytes(4 * 1000)	b.ResetTimer()	for i := 0; i < b.N; i++ {		buf.Reset()		Write(w, BigEndian, slice)	}	b.StopTimer()}