// Protocol Buffers for Go with Gadgets
|
|
//
|
|
// Copyright (c) 2013, The GoGo Authors. All rights reserved.
|
|
// http://github.com/gogo/protobuf
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
// in the documentation and/or other materials provided with the
|
|
// distribution.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
package protoio_test
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
"math/rand"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gogo/protobuf/proto"
|
|
"github.com/gogo/protobuf/test"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/tendermint/tendermint/internal/libs/protoio"
|
|
)
|
|
|
|
func iotest(t *testing.T, writer protoio.WriteCloser, reader protoio.ReadCloser) error {
|
|
t.Helper()
|
|
varint := make([]byte, binary.MaxVarintLen64)
|
|
size := 1000
|
|
msgs := make([]*test.NinOptNative, size)
|
|
lens := make([]int, size)
|
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
for i := range msgs {
|
|
msgs[i] = test.NewPopulatedNinOptNative(r, true)
|
|
// issue 31
|
|
if i == 5 {
|
|
msgs[i] = &test.NinOptNative{}
|
|
}
|
|
// issue 31
|
|
if i == 999 {
|
|
msgs[i] = &test.NinOptNative{}
|
|
}
|
|
// FIXME Check size
|
|
bz, err := proto.Marshal(msgs[i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
visize := binary.PutUvarint(varint, uint64(len(bz)))
|
|
n, err := writer.WriteMsg(msgs[i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if n != len(bz)+visize {
|
|
return fmt.Errorf("WriteMsg() wrote %v bytes, expected %v", n, len(bz)+visize)
|
|
}
|
|
lens[i] = n
|
|
}
|
|
if err := writer.Close(); err != nil {
|
|
return err
|
|
}
|
|
i := 0
|
|
for {
|
|
msg := &test.NinOptNative{}
|
|
if n, err := reader.ReadMsg(msg); err != nil {
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
return err
|
|
} else if n != lens[i] {
|
|
return fmt.Errorf("read %v bytes, expected %v", n, lens[i])
|
|
}
|
|
if err := msg.VerboseEqual(msgs[i]); err != nil {
|
|
return err
|
|
}
|
|
i++
|
|
}
|
|
require.Equal(t, size, i, "messages read ≠ messages written")
|
|
if err := reader.Close(); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type buffer struct {
|
|
*bytes.Buffer
|
|
closed bool
|
|
}
|
|
|
|
func (b *buffer) Close() error {
|
|
b.closed = true
|
|
return nil
|
|
}
|
|
|
|
func newBuffer() *buffer {
|
|
return &buffer{bytes.NewBuffer(nil), false}
|
|
}
|
|
|
|
func TestVarintNormal(t *testing.T) {
|
|
buf := newBuffer()
|
|
writer := protoio.NewDelimitedWriter(buf)
|
|
reader := protoio.NewDelimitedReader(buf, 1024*1024)
|
|
err := iotest(t, writer, reader)
|
|
require.NoError(t, err)
|
|
require.True(t, buf.closed, "did not close buffer")
|
|
}
|
|
|
|
func TestVarintNoClose(t *testing.T) {
|
|
buf := bytes.NewBuffer(nil)
|
|
writer := protoio.NewDelimitedWriter(buf)
|
|
reader := protoio.NewDelimitedReader(buf, 1024*1024)
|
|
err := iotest(t, writer, reader)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// issue 32
|
|
func TestVarintMaxSize(t *testing.T) {
|
|
buf := newBuffer()
|
|
writer := protoio.NewDelimitedWriter(buf)
|
|
reader := protoio.NewDelimitedReader(buf, 20)
|
|
err := iotest(t, writer, reader)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestVarintError(t *testing.T) {
|
|
buf := newBuffer()
|
|
buf.Write([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f})
|
|
reader := protoio.NewDelimitedReader(buf, 1024*1024)
|
|
msg := &test.NinOptNative{}
|
|
n, err := reader.ReadMsg(msg)
|
|
require.Error(t, err)
|
|
require.Equal(t, 10, n)
|
|
}
|
|
|
|
func TestVarintTruncated(t *testing.T) {
|
|
buf := newBuffer()
|
|
buf.Write([]byte{0xff, 0xff})
|
|
reader := protoio.NewDelimitedReader(buf, 1024*1024)
|
|
msg := &test.NinOptNative{}
|
|
n, err := reader.ReadMsg(msg)
|
|
require.Error(t, err)
|
|
require.Equal(t, 2, n)
|
|
}
|
|
|
|
func TestShort(t *testing.T) {
|
|
buf := newBuffer()
|
|
|
|
varintBuf := make([]byte, binary.MaxVarintLen64)
|
|
varintLen := binary.PutUvarint(varintBuf, 100)
|
|
_, err := buf.Write(varintBuf[:varintLen])
|
|
require.NoError(t, err)
|
|
|
|
bz, err := proto.Marshal(&test.NinOptNative{Field15: []byte{0x01, 0x02, 0x03}})
|
|
require.NoError(t, err)
|
|
buf.Write(bz)
|
|
|
|
reader := protoio.NewDelimitedReader(buf, 1024*1024)
|
|
require.NoError(t, err)
|
|
msg := &test.NinOptNative{}
|
|
n, err := reader.ReadMsg(msg)
|
|
require.Error(t, err)
|
|
require.Equal(t, varintLen+len(bz), n)
|
|
}
|