neo-go/pkg/io/binaryrw_test.go
2020-06-22 15:35:42 +03:00

488 lines
11 KiB
Go

package io
import (
"errors"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// mocks io.Reader and io.Writer, always fails to Write() or Read().
type badRW struct{}
func (w *badRW) Write(p []byte) (int, error) {
return 0, errors.New("it always fails")
}
func (w *badRW) Read(p []byte) (int, error) {
return w.Write(p)
}
func TestWriteU64LE(t *testing.T) {
var (
val uint64 = 0xbadc0de15a11dead
readval uint64
bin = []byte{0xad, 0xde, 0x11, 0x5a, 0xe1, 0x0d, 0xdc, 0xba}
)
bw := NewBufBinWriter()
bw.WriteU64LE(val)
assert.Nil(t, bw.Err)
wrotebin := bw.Bytes()
assert.Equal(t, wrotebin, bin)
br := NewBinReaderFromBuf(bin)
readval = br.ReadU64LE()
assert.Nil(t, br.Err)
assert.Equal(t, val, readval)
}
func TestWriteU32LE(t *testing.T) {
var (
val uint32 = 0xdeadbeef
readval uint32
bin = []byte{0xef, 0xbe, 0xad, 0xde}
)
bw := NewBufBinWriter()
bw.WriteU32LE(val)
assert.Nil(t, bw.Err)
wrotebin := bw.Bytes()
assert.Equal(t, wrotebin, bin)
br := NewBinReaderFromBuf(bin)
readval = br.ReadU32LE()
assert.Nil(t, br.Err)
assert.Equal(t, val, readval)
}
func TestWriteU16LE(t *testing.T) {
var (
val uint16 = 0xbabe
readval uint16
bin = []byte{0xbe, 0xba}
)
bw := NewBufBinWriter()
bw.WriteU16LE(val)
assert.Nil(t, bw.Err)
wrotebin := bw.Bytes()
assert.Equal(t, wrotebin, bin)
br := NewBinReaderFromBuf(bin)
readval = br.ReadU16LE()
assert.Nil(t, br.Err)
assert.Equal(t, val, readval)
}
func TestWriteU16BE(t *testing.T) {
var (
val uint16 = 0xbabe
readval uint16
bin = []byte{0xba, 0xbe}
)
bw := NewBufBinWriter()
bw.WriteU16BE(val)
assert.Nil(t, bw.Err)
wrotebin := bw.Bytes()
assert.Equal(t, wrotebin, bin)
br := NewBinReaderFromBuf(bin)
readval = br.ReadU16BE()
assert.Nil(t, br.Err)
assert.Equal(t, val, readval)
}
func TestWriteByte(t *testing.T) {
var (
val byte = 0xa5
readval byte
bin = []byte{0xa5}
)
bw := NewBufBinWriter()
bw.WriteB(val)
assert.Nil(t, bw.Err)
wrotebin := bw.Bytes()
assert.Equal(t, wrotebin, bin)
br := NewBinReaderFromBuf(bin)
readval = br.ReadB()
assert.Nil(t, br.Err)
assert.Equal(t, val, readval)
}
func TestWriteBool(t *testing.T) {
var (
bin = []byte{0x01, 0x00}
)
bw := NewBufBinWriter()
bw.WriteBool(true)
bw.WriteBool(false)
assert.Nil(t, bw.Err)
wrotebin := bw.Bytes()
assert.Equal(t, wrotebin, bin)
br := NewBinReaderFromBuf(bin)
assert.Equal(t, true, br.ReadBool())
assert.Equal(t, false, br.ReadBool())
assert.Nil(t, br.Err)
}
func TestReadLEErrors(t *testing.T) {
bin := []byte{0xad, 0xde, 0x11, 0x5a, 0xe1, 0x0d, 0xdc, 0xba}
br := NewBinReaderFromBuf(bin)
// Prime the buffers with something.
_ = br.ReadU64LE()
assert.Nil(t, br.Err)
assert.Equal(t, uint64(0), br.ReadU64LE())
assert.Equal(t, uint32(0), br.ReadU32LE())
assert.Equal(t, uint16(0), br.ReadU16LE())
assert.Equal(t, uint16(0), br.ReadU16BE())
assert.Equal(t, byte(0), br.ReadB())
assert.Equal(t, false, br.ReadBool())
assert.NotNil(t, br.Err)
}
func TestBufBinWriter_Len(t *testing.T) {
val := []byte{0xde}
bw := NewBufBinWriter()
bw.WriteBytes(val)
require.Equal(t, 1, bw.Len())
}
func TestBinReader_ReadVarBytes(t *testing.T) {
buf := make([]byte, 11)
for i := range buf {
buf[i] = byte(i)
}
w := NewBufBinWriter()
w.WriteVarBytes(buf)
require.NoError(t, w.Err)
data := w.Bytes()
t.Run("NoArguments", func(t *testing.T) {
r := NewBinReaderFromBuf(data)
actual := r.ReadVarBytes()
require.NoError(t, r.Err)
require.Equal(t, buf, actual)
})
t.Run("Good", func(t *testing.T) {
r := NewBinReaderFromBuf(data)
actual := r.ReadVarBytes(11)
require.NoError(t, r.Err)
require.Equal(t, buf, actual)
})
t.Run("Bad", func(t *testing.T) {
r := NewBinReaderFromBuf(data)
r.ReadVarBytes(10)
require.Error(t, r.Err)
})
}
func TestWriterErrHandling(t *testing.T) {
var badio = &badRW{}
bw := NewBinWriterFromIO(badio)
bw.WriteU32LE(uint32(0))
assert.NotNil(t, bw.Err)
// these should work (without panic), preserving the Err
bw.WriteU32LE(uint32(0))
bw.WriteU16BE(uint16(0))
bw.WriteVarUint(0)
bw.WriteVarBytes([]byte{0x55, 0xaa})
bw.WriteString("neo")
assert.NotNil(t, bw.Err)
}
func TestReaderErrHandling(t *testing.T) {
var (
badio = &badRW{}
)
br := NewBinReaderFromIO(badio)
br.ReadU32LE()
assert.NotNil(t, br.Err)
// these should work (without panic), preserving the Err
br.ReadU32LE()
br.ReadU16BE()
val := br.ReadVarUint()
assert.Equal(t, val, uint64(0))
b := br.ReadVarBytes()
assert.Equal(t, b, []byte{})
s := br.ReadString()
assert.Equal(t, s, "")
assert.NotNil(t, br.Err)
}
func TestBufBinWriterErr(t *testing.T) {
bw := NewBufBinWriter()
bw.WriteU32LE(uint32(0))
assert.Nil(t, bw.Err)
// inject error
bw.Err = errors.New("oopsie")
res := bw.Bytes()
assert.NotNil(t, bw.Err)
assert.Nil(t, res)
}
func TestBufBinWriterReset(t *testing.T) {
bw := NewBufBinWriter()
for i := 0; i < 3; i++ {
bw.WriteU32LE(uint32(i))
assert.Nil(t, bw.Err)
_ = bw.Bytes()
assert.NotNil(t, bw.Err)
bw.Reset()
assert.Nil(t, bw.Err)
}
}
func TestWriteString(t *testing.T) {
var (
str = "teststring"
)
bw := NewBufBinWriter()
bw.WriteString(str)
assert.Nil(t, bw.Err)
wrotebin := bw.Bytes()
// +1 byte for length
assert.Equal(t, len(wrotebin), len(str)+1)
br := NewBinReaderFromBuf(wrotebin)
readstr := br.ReadString()
assert.Nil(t, br.Err)
assert.Equal(t, str, readstr)
}
func TestWriteVarUint1(t *testing.T) {
var (
val = uint64(1)
)
bw := NewBufBinWriter()
bw.WriteVarUint(val)
assert.Nil(t, bw.Err)
buf := bw.Bytes()
assert.Equal(t, 1, len(buf))
br := NewBinReaderFromBuf(buf)
res := br.ReadVarUint()
assert.Nil(t, br.Err)
assert.Equal(t, val, res)
}
func TestWriteVarUint1000(t *testing.T) {
var (
val = uint64(1000)
)
bw := NewBufBinWriter()
bw.WriteVarUint(val)
assert.Nil(t, bw.Err)
buf := bw.Bytes()
assert.Equal(t, 3, len(buf))
assert.Equal(t, byte(0xfd), buf[0])
br := NewBinReaderFromBuf(buf)
res := br.ReadVarUint()
assert.Nil(t, br.Err)
assert.Equal(t, val, res)
}
func TestWriteVarUint100000(t *testing.T) {
var (
val = uint64(100000)
)
bw := NewBufBinWriter()
bw.WriteVarUint(val)
assert.Nil(t, bw.Err)
buf := bw.Bytes()
assert.Equal(t, 5, len(buf))
assert.Equal(t, byte(0xfe), buf[0])
br := NewBinReaderFromBuf(buf)
res := br.ReadVarUint()
assert.Nil(t, br.Err)
assert.Equal(t, val, res)
}
func TestWriteVarUint100000000000(t *testing.T) {
var (
val = uint64(1000000000000)
)
bw := NewBufBinWriter()
bw.WriteVarUint(val)
assert.Nil(t, bw.Err)
buf := bw.Bytes()
assert.Equal(t, 9, len(buf))
assert.Equal(t, byte(0xff), buf[0])
br := NewBinReaderFromBuf(buf)
res := br.ReadVarUint()
assert.Nil(t, br.Err)
assert.Equal(t, val, res)
}
func TestWriteBytes(t *testing.T) {
var (
bin = []byte{0xde, 0xad, 0xbe, 0xef}
)
bw := NewBufBinWriter()
bw.WriteBytes(bin)
assert.Nil(t, bw.Err)
buf := bw.Bytes()
assert.Equal(t, 4, len(buf))
assert.Equal(t, byte(0xde), buf[0])
bw = NewBufBinWriter()
bw.Err = errors.New("smth bad")
bw.WriteBytes(bin)
assert.Equal(t, 0, bw.Len())
}
type testSerializable uint16
// EncodeBinary implements io.Serializable interface.
func (t testSerializable) EncodeBinary(w *BinWriter) {
w.WriteU16LE(uint16(t))
}
// DecodeBinary implements io.Serializable interface.
func (t *testSerializable) DecodeBinary(r *BinReader) {
*t = testSerializable(r.ReadU16LE())
}
type testPtrSerializable uint16
// EncodeBinary implements io.Serializable interface.
func (t *testPtrSerializable) EncodeBinary(w *BinWriter) {
w.WriteU16LE(uint16(*t))
}
// DecodeBinary implements io.Serializable interface.
func (t *testPtrSerializable) DecodeBinary(r *BinReader) {
*t = testPtrSerializable(r.ReadU16LE())
}
func TestBinWriter_WriteArray(t *testing.T) {
var arr [3]testSerializable
for i := range arr {
arr[i] = testSerializable(i)
}
expected := []byte{3, 0, 0, 1, 0, 2, 0}
w := NewBufBinWriter()
w.WriteArray(arr)
require.NoError(t, w.Err)
require.Equal(t, expected, w.Bytes())
w.Reset()
w.WriteArray(arr[:])
require.NoError(t, w.Err)
require.Equal(t, expected, w.Bytes())
arrS := make([]Serializable, len(arr))
for i := range arrS {
arrS[i] = &arr[i]
}
w.Reset()
w.WriteArray(arr)
require.NoError(t, w.Err)
require.Equal(t, expected, w.Bytes())
w.Reset()
require.Panics(t, func() { w.WriteArray(1) })
w.Reset()
w.Err = errors.New("error")
w.WriteArray(arr[:])
require.Error(t, w.Err)
require.Equal(t, w.Bytes(), []byte(nil))
w.Reset()
require.Panics(t, func() { w.WriteArray([]int{1}) })
w.Reset()
w.Err = errors.New("error")
require.Panics(t, func() { w.WriteArray(make(chan testSerializable)) })
// Ptr receiver test
var arrPtr [3]testPtrSerializable
for i := range arrPtr {
arrPtr[i] = testPtrSerializable(i)
}
w.Reset()
w.WriteArray(arr[:])
require.NoError(t, w.Err)
require.Equal(t, expected, w.Bytes())
}
func TestBinReader_ReadArray(t *testing.T) {
data := []byte{3, 0, 0, 1, 0, 2, 0}
elems := []testSerializable{0, 1, 2}
r := NewBinReaderFromBuf(data)
arrPtr := []*testSerializable{}
r.ReadArray(&arrPtr)
require.Equal(t, []*testSerializable{&elems[0], &elems[1], &elems[2]}, arrPtr)
r = NewBinReaderFromBuf(data)
arrVal := []testSerializable{}
r.ReadArray(&arrVal)
require.NoError(t, r.Err)
require.Equal(t, elems, arrVal)
r = NewBinReaderFromBuf(data)
arrVal = []testSerializable{}
r.ReadArray(&arrVal, 3)
require.NoError(t, r.Err)
require.Equal(t, elems, arrVal)
r = NewBinReaderFromBuf(data)
arrVal = []testSerializable{}
r.ReadArray(&arrVal, 2)
require.Error(t, r.Err)
r = NewBinReaderFromBuf([]byte{0})
r.ReadArray(&arrVal)
require.NoError(t, r.Err)
require.Equal(t, []testSerializable{}, arrVal)
r = NewBinReaderFromBuf([]byte{0})
r.Err = errors.New("error")
arrVal = ([]testSerializable)(nil)
r.ReadArray(&arrVal)
require.Error(t, r.Err)
require.Equal(t, ([]testSerializable)(nil), arrVal)
r = NewBinReaderFromBuf([]byte{0})
r.Err = errors.New("error")
arrPtr = ([]*testSerializable)(nil)
r.ReadArray(&arrVal)
require.Error(t, r.Err)
require.Equal(t, ([]*testSerializable)(nil), arrPtr)
r = NewBinReaderFromBuf([]byte{0})
arrVal = []testSerializable{1, 2}
r.ReadArray(&arrVal)
require.NoError(t, r.Err)
require.Equal(t, []testSerializable{}, arrVal)
r = NewBinReaderFromBuf([]byte{1})
require.Panics(t, func() { r.ReadArray(&[]int{1}) })
r = NewBinReaderFromBuf([]byte{0})
r.Err = errors.New("error")
require.Panics(t, func() { r.ReadArray(1) })
}
func TestBinReader_ReadBytes(t *testing.T) {
data := []byte{0, 1, 2, 3, 4, 5, 6, 7}
r := NewBinReaderFromBuf(data)
buf := make([]byte, 4)
r.ReadBytes(buf)
require.NoError(t, r.Err)
require.Equal(t, data[:4], buf)
r.ReadBytes([]byte{})
require.NoError(t, r.Err)
buf = make([]byte, 3)
r.ReadBytes(buf)
require.NoError(t, r.Err)
require.Equal(t, data[4:7], buf)
buf = make([]byte, 2)
r.ReadBytes(buf)
require.Error(t, r.Err)
r.ReadBytes([]byte{})
require.Error(t, r.Err)
}