915 lines
20 KiB
Go
915 lines
20 KiB
Go
package buffer
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"encoding/gob"
|
|
"errors"
|
|
"io"
|
|
"io/ioutil"
|
|
"math"
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
func BenchmarkMemory(b *testing.B) {
|
|
buf := New(32 * 1024)
|
|
for i := 0; i < b.N; i++ {
|
|
io.Copy(buf, io.LimitReader(rand.Reader, 32*1024))
|
|
io.Copy(ioutil.Discard, buf)
|
|
}
|
|
}
|
|
|
|
func TestPool(t *testing.T) {
|
|
pool := NewPool(func() Buffer { return New(10) })
|
|
buf, err := pool.Get()
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
buf.Write([]byte("hello world"))
|
|
pool.Put(buf)
|
|
}
|
|
|
|
func TestMemPool(t *testing.T) {
|
|
p := NewMemPool(10)
|
|
poolTest(p, t)
|
|
|
|
b := bytes.NewBuffer(nil)
|
|
enc := gob.NewEncoder(b)
|
|
if err := enc.Encode(&p); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
var pool Pool
|
|
dec := gob.NewDecoder(b)
|
|
if err := dec.Decode(&pool); err != nil {
|
|
t.Error(err)
|
|
}
|
|
poolTest(pool, t)
|
|
}
|
|
|
|
func poolTest(pool Pool, t *testing.T) {
|
|
buf, err := pool.Get()
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if n, err := buf.Write([]byte("hello world")); n != 10 {
|
|
t.Errorf("wrote incorrect amount")
|
|
} else if err == nil {
|
|
t.Errorf("should have been a shortwrite error here")
|
|
}
|
|
pool.Put(buf)
|
|
if buf.Len() > 0 {
|
|
t.Errorf("should have emptied the buffer")
|
|
}
|
|
}
|
|
|
|
func TestFilePool(t *testing.T) {
|
|
pool := NewFilePool(1024, "::~_bad_dir_~::")
|
|
buf := NewPartition(pool)
|
|
_, err := buf.Write([]byte("hello"))
|
|
if err == nil {
|
|
t.Error("an error was expected here")
|
|
}
|
|
}
|
|
|
|
func TestFilePool2(t *testing.T) {
|
|
pool := NewFilePool(1024, "::~_bad_dir_~::")
|
|
buf := NewPartition(pool, New(0))
|
|
_, err := buf.Write([]byte("hello"))
|
|
if err == nil {
|
|
t.Error("an error was expected here")
|
|
}
|
|
}
|
|
|
|
func TestOverflow(t *testing.T) {
|
|
buf := NewMulti(New(5), Discard)
|
|
buf.Write([]byte("Hello World"))
|
|
|
|
b := bytes.NewBuffer(nil)
|
|
enc := gob.NewEncoder(b)
|
|
if err := enc.Encode(&buf); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
var buf2 Buffer
|
|
dec := gob.NewDecoder(b)
|
|
if err := dec.Decode(&buf2); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
buf = buf2
|
|
|
|
data, err := ioutil.ReadAll(buf)
|
|
if err != nil {
|
|
t.Error(err.Error())
|
|
}
|
|
|
|
if !bytes.Equal(data, []byte("Hello")) {
|
|
t.Errorf("Expected Hello got %s", string(data))
|
|
}
|
|
|
|
}
|
|
|
|
func TestWriteAt(t *testing.T) {
|
|
var b BufferAt
|
|
|
|
b = New(5)
|
|
BufferAtTester(t, b)
|
|
|
|
file, err := ioutil.TempFile("", "buffer")
|
|
if err != nil {
|
|
t.Error(err.Error())
|
|
}
|
|
defer os.Remove(file.Name())
|
|
defer file.Close()
|
|
|
|
b = NewFile(5, file)
|
|
BufferAtTester(t, b)
|
|
|
|
b = NewMultiAt(New(1), NewFile(4, file))
|
|
BufferAtTester(t, b)
|
|
|
|
b = NewMultiAt(New(2), NewFile(3, file))
|
|
BufferAtTester(t, b)
|
|
|
|
b = NewMultiAt(New(3), NewFile(2, file))
|
|
BufferAtTester(t, b)
|
|
|
|
b = NewMultiAt(New(4), NewFile(1, file))
|
|
BufferAtTester(t, b)
|
|
|
|
b = NewSwapAt(New(1), New(5))
|
|
BufferAtTester(t, b)
|
|
|
|
b = NewSwapAt(New(2), New(5))
|
|
BufferAtTester(t, b)
|
|
|
|
b = NewSwapAt(New(3), New(5))
|
|
BufferAtTester(t, b)
|
|
|
|
b = NewSwapAt(New(4), New(5))
|
|
BufferAtTester(t, b)
|
|
|
|
b = NewPartitionAt(NewMemPoolAt(3))
|
|
BufferAtTester(t, b)
|
|
|
|
b = NewPartitionAt(NewFilePoolAt(3, os.TempDir()))
|
|
BufferAtTester(t, b)
|
|
|
|
b = NewPartitionAt(NewMemPoolAt(1))
|
|
BufferAtTester(t, b)
|
|
|
|
b = NewPartitionAt(NewFilePoolAt(1, os.TempDir()))
|
|
BufferAtTester(t, b)
|
|
|
|
b = NewPartitionAt(NewMemPoolAt(5))
|
|
BufferAtTester(t, b)
|
|
|
|
b = NewPartitionAt(NewFilePoolAt(5, os.TempDir()))
|
|
BufferAtTester(t, b)
|
|
}
|
|
|
|
func BufferAtTester(t *testing.T, b BufferAt) {
|
|
t.Helper()
|
|
b.WriteAt([]byte("abc"), 0)
|
|
Compare(t, b, "abc")
|
|
|
|
b.WriteAt([]byte("abc"), 1)
|
|
Compare(t, b, "aabc")
|
|
|
|
b.WriteAt([]byte("abc"), 2)
|
|
Compare(t, b, "aaabc")
|
|
|
|
b.WriteAt([]byte("def"), 3)
|
|
switch {
|
|
case b.Cap() > 5:
|
|
Compare(t, b, "aaadef")
|
|
default:
|
|
Compare(t, b, "aaade")
|
|
}
|
|
|
|
b.Read(make([]byte, 2))
|
|
switch {
|
|
case b.Cap() > 5:
|
|
Compare(t, b, "adef")
|
|
default:
|
|
Compare(t, b, "ade")
|
|
}
|
|
|
|
b.WriteAt([]byte("ab"), 3)
|
|
Compare(t, b, "adeab")
|
|
|
|
b.Reset()
|
|
}
|
|
|
|
func Compare(t *testing.T, b BufferAt, s string) {
|
|
t.Helper()
|
|
data := make([]byte, b.Len())
|
|
n, _ := b.ReadAt(data, 0)
|
|
if string(data[:n]) != s {
|
|
t.Errorf("Mismatch: got %q want %q", string(data[:n]), s)
|
|
}
|
|
off := int64(len(s) / 2)
|
|
n, _ = b.ReadAt(data, off)
|
|
if string(data[:n]) != s[off:] {
|
|
t.Errorf("Mismatch: got %q want %q", string(data[:n]), s[off:])
|
|
}
|
|
}
|
|
|
|
func TestRingComplex(t *testing.T) {
|
|
ringSize := 10
|
|
data := []byte("hello!")
|
|
ring := NewRing(New(int64(ringSize)))
|
|
buf := make([]byte, ringSize)
|
|
|
|
for i := 0; i < 10; i++ {
|
|
ring.Write(data)
|
|
n, err := ring.Read(buf)
|
|
if err != nil {
|
|
t.Errorf("unexpected error %s", err)
|
|
} else if !bytes.Equal(buf[:n], data) {
|
|
t.Errorf("expected %s got %s", data, buf[:n])
|
|
}
|
|
}
|
|
|
|
// we are going to overflow the buffer here, we expect the last 10 bytes to remain
|
|
repData := bytes.Repeat(data, 3)
|
|
leftover := repData[len(repData)-ringSize:]
|
|
for i := 0; i < 10; i++ {
|
|
ring.Write(repData)
|
|
n, err := ring.Read(buf)
|
|
if err != nil {
|
|
t.Errorf("unexpected error %s", err)
|
|
} else if !bytes.Equal(buf[:n], leftover) {
|
|
t.Errorf("expected %s got %s", leftover, buf[:n])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRing(t *testing.T) {
|
|
ring := NewRing(New(3))
|
|
if ring.Len() != 0 {
|
|
t.Errorf("Ring non-empty start!")
|
|
}
|
|
|
|
if ring.Cap() != math.MaxInt64 {
|
|
t.Errorf("Ring has < max capacity")
|
|
}
|
|
|
|
ring.Write([]byte("abc"))
|
|
if ring.Len() != 3 {
|
|
t.Errorf("expected ring len == 3")
|
|
}
|
|
|
|
ring.Write([]byte("de"))
|
|
if ring.Len() != 3 {
|
|
t.Errorf("expected ring len == 3")
|
|
}
|
|
|
|
data := make([]byte, 12)
|
|
if n, err := ring.Read(data); err != nil {
|
|
t.Error(err.Error())
|
|
} else {
|
|
if !bytes.Equal(data[:n], []byte("cde")) {
|
|
t.Errorf("expected cde, got %s", data[:n])
|
|
}
|
|
}
|
|
|
|
if ring.Len() != 0 {
|
|
t.Errorf("ring should now be empty")
|
|
}
|
|
|
|
ring.Write([]byte("hello"))
|
|
ring.Reset()
|
|
|
|
if ring.Len() != 0 {
|
|
t.Errorf("ring should still be empty")
|
|
}
|
|
}
|
|
|
|
func TestGob(t *testing.T) {
|
|
str := "HelloWorld"
|
|
|
|
buf := NewUnboundedBuffer(2, 2)
|
|
buf.Write([]byte(str))
|
|
b := bytes.NewBuffer(nil)
|
|
if err := gob.NewEncoder(b).Encode(&buf); err != nil {
|
|
t.Error(err.Error())
|
|
return
|
|
}
|
|
var buffer Buffer
|
|
if err := gob.NewDecoder(b).Decode(&buffer); err != nil {
|
|
t.Error(err.Error())
|
|
return
|
|
}
|
|
data := make([]byte, len(str))
|
|
if _, err := buffer.Read(data); err != nil && err != io.EOF {
|
|
t.Error(err.Error())
|
|
}
|
|
if !bytes.Equal(data, []byte(str)) {
|
|
t.Error("Gob Recover Failed... " + string(data))
|
|
}
|
|
buffer.Reset()
|
|
}
|
|
|
|
func TestDiscard(t *testing.T) {
|
|
buf := Discard
|
|
if buf.Cap() != math.MaxInt64 {
|
|
t.Errorf("cap isn't infinite")
|
|
}
|
|
buf.Write([]byte("hello"))
|
|
if buf.Len() != 0 {
|
|
t.Errorf("buf should always be empty")
|
|
}
|
|
}
|
|
|
|
func TestList(t *testing.T) {
|
|
mem := New(10)
|
|
ory := New(10)
|
|
mem.Write([]byte("Hello"))
|
|
ory.Write([]byte("world"))
|
|
|
|
buf := List([]Buffer{mem, ory, Discard})
|
|
if buf.Len() != 10 {
|
|
t.Errorf("incorrect sum of lengths")
|
|
}
|
|
if buf.Cap() != math.MaxInt64 {
|
|
t.Errorf("incorrect sum of caps")
|
|
}
|
|
|
|
buf.Reset()
|
|
if buf.Len() != 0 {
|
|
t.Errorf("buffer should be empty")
|
|
}
|
|
}
|
|
|
|
func TestList2(t *testing.T) {
|
|
mem := New(10)
|
|
ory := New(10)
|
|
mem.Write([]byte("Hello"))
|
|
ory.Write([]byte("world"))
|
|
|
|
buf := List([]Buffer{mem, ory})
|
|
if buf.Len() != 10 {
|
|
t.Errorf("incorrect sum of lengths")
|
|
}
|
|
if buf.Cap() != 20 {
|
|
t.Errorf("incorrect sum of caps")
|
|
}
|
|
|
|
buf.Reset()
|
|
if buf.Len() != 0 {
|
|
t.Errorf("buffer should be empty")
|
|
}
|
|
}
|
|
|
|
func TestSpill(t *testing.T) {
|
|
buf := NewSpill(New(5), Discard)
|
|
buf.Write([]byte("Hello World"))
|
|
data := make([]byte, 12)
|
|
n, _ := buf.Read(data)
|
|
if !bytes.Equal(data[:n], []byte("Hello")) {
|
|
t.Error("ReadAt Failed. " + string(data[:n]))
|
|
}
|
|
}
|
|
|
|
func TestSpill2(t *testing.T) {
|
|
buf := NewSpill(New(5), nil)
|
|
|
|
if buf.Cap() != math.MaxInt64 {
|
|
t.Errorf("cap isn't infinite")
|
|
}
|
|
|
|
towrite := []byte("Hello World")
|
|
m, _ := buf.Write(towrite)
|
|
if m != len(towrite) {
|
|
t.Errorf("failed to write all data: %d != %d", m, len(towrite))
|
|
}
|
|
data := make([]byte, 12)
|
|
n, _ := buf.Read(data)
|
|
if !bytes.Equal(data[:n], []byte("Hello")) {
|
|
t.Error("Read Failed. " + string(data[:n]))
|
|
}
|
|
}
|
|
|
|
func TestNoSpill(t *testing.T) {
|
|
buf := NewSpill(New(1024), nil)
|
|
buf.Write([]byte("Hello World"))
|
|
data := make([]byte, 12)
|
|
n, _ := buf.Read(data)
|
|
if !bytes.Equal(data[:n], []byte("Hello World")) {
|
|
t.Error("Read Failed. " + string(data[:n]))
|
|
}
|
|
}
|
|
|
|
func TestFile(t *testing.T) {
|
|
file, err := ioutil.TempFile("", "buffer")
|
|
if err != nil {
|
|
t.Error(err.Error())
|
|
}
|
|
defer os.Remove(file.Name())
|
|
defer file.Close()
|
|
|
|
buf := NewFile(1024, file)
|
|
checkCap(t, buf, 1024)
|
|
runPerfectSeries(t, buf)
|
|
buf.Reset()
|
|
|
|
buf = NewFile(3, file)
|
|
buf.Write([]byte("abc"))
|
|
buf.Read(make([]byte, 1))
|
|
buf.Write([]byte("a"))
|
|
d, _ := ioutil.ReadAll(buf)
|
|
if !bytes.Equal(d, []byte("bca")) {
|
|
t.Error("back and forth error!")
|
|
}
|
|
}
|
|
|
|
func TestMem(t *testing.T) {
|
|
buf := New(1024)
|
|
checkCap(t, buf, 1024)
|
|
runPerfectSeries(t, buf)
|
|
buf.Reset()
|
|
if n, err := buf.WriteAt([]byte("hello"), 1); err == nil || n != 0 {
|
|
t.Errorf("write should have failed")
|
|
}
|
|
}
|
|
|
|
func TestFilePartition(t *testing.T) {
|
|
buf := NewPartition(NewFilePool(1024, ""))
|
|
checkCap(t, buf, math.MaxInt64)
|
|
runPerfectSeries(t, buf)
|
|
buf.Reset()
|
|
}
|
|
|
|
func TestSmallMulti(t *testing.T) {
|
|
if empty := NewMulti(); empty != nil {
|
|
t.Errorf("the empty buffer should return nil")
|
|
}
|
|
|
|
one := NewMulti(New(10))
|
|
if one.Len() != 0 {
|
|
t.Errorf("singleton multi doesn't match inner buffer len")
|
|
}
|
|
if one.Cap() != 10 {
|
|
t.Errorf("singleton multi doesn't match inner buffer cap")
|
|
}
|
|
}
|
|
|
|
func TestMulti(t *testing.T) {
|
|
file, err := ioutil.TempFile("", "buffer")
|
|
if err != nil {
|
|
t.Error(err.Error())
|
|
}
|
|
defer os.Remove(file.Name())
|
|
defer file.Close()
|
|
|
|
buf := NewMulti(New(5), New(5), NewFile(500, file), NewPartition(NewFilePool(1024, "")))
|
|
checkCap(t, buf, math.MaxInt64)
|
|
runPerfectSeries(t, buf)
|
|
isPerfectMatch(t, buf, 1024*1024)
|
|
buf.Reset()
|
|
}
|
|
|
|
func TestMulti2(t *testing.T) {
|
|
file, err := ioutil.TempFile("", "buffer")
|
|
if err != nil {
|
|
t.Error(err.Error())
|
|
}
|
|
defer os.Remove(file.Name())
|
|
defer file.Close()
|
|
|
|
buf := NewMulti(New(5), New(5), NewFile(500, file))
|
|
checkCap(t, buf, 510)
|
|
runPerfectSeries(t, buf)
|
|
isPerfectMatch(t, buf, 1024*1024)
|
|
buf.Reset()
|
|
}
|
|
|
|
func runPerfectSeries(t *testing.T, buf Buffer) {
|
|
checkEmpty(t, buf)
|
|
simple(t, buf)
|
|
|
|
max := int64(1024)
|
|
isPerfectMatch(t, buf, 0)
|
|
for i := int64(1); i < max; i *= 2 {
|
|
isPerfectMatch(t, buf, i)
|
|
}
|
|
isPerfectMatch(t, buf, max)
|
|
}
|
|
|
|
func simple(t *testing.T, buf Buffer) {
|
|
buf.Write([]byte("hello world"))
|
|
data, err := ioutil.ReadAll(buf)
|
|
if err != nil {
|
|
t.Error(err.Error())
|
|
}
|
|
if !bytes.Equal([]byte("hello world"), data) {
|
|
t.Error("Hello world failed.")
|
|
}
|
|
|
|
buf.Write([]byte("hello world"))
|
|
data = make([]byte, 3)
|
|
buf.Read(data)
|
|
buf.Write([]byte(" yolo"))
|
|
data, err = ioutil.ReadAll(buf)
|
|
if err != nil {
|
|
t.Error(err.Error())
|
|
}
|
|
if !bytes.Equal([]byte("lo world yolo"), data) {
|
|
t.Error("Buffer crossing error :(", string(data))
|
|
}
|
|
}
|
|
|
|
func buildOutputs(t *testing.T, buf Buffer, size int64) (wrote []byte, read []byte) {
|
|
r := io.LimitReader(rand.Reader, size)
|
|
tee := io.TeeReader(r, buf)
|
|
|
|
wrote, _ = ioutil.ReadAll(tee)
|
|
read, _ = ioutil.ReadAll(buf)
|
|
|
|
return wrote, read
|
|
}
|
|
|
|
func isPerfectMatch(t *testing.T, buf Buffer, size int64) {
|
|
wrote, read := buildOutputs(t, buf, size)
|
|
if !bytes.Equal(wrote, read) {
|
|
t.Error("Buffer should have matched")
|
|
}
|
|
}
|
|
|
|
func checkEmpty(t *testing.T, buf Buffer) {
|
|
if !Empty(buf) {
|
|
t.Error("Buffer should start empty!")
|
|
}
|
|
}
|
|
|
|
func checkCap(t *testing.T, buf Buffer, correctCap int64) {
|
|
if buf.Cap() != correctCap {
|
|
t.Error("Buffer cap is incorrect", buf.Cap(), correctCap)
|
|
}
|
|
}
|
|
|
|
type bigBuffer struct{}
|
|
|
|
func (b bigBuffer) Len() int64 { return math.MaxInt64 }
|
|
|
|
func (b bigBuffer) Cap() int64 { return math.MaxInt64 }
|
|
|
|
func (b bigBuffer) Read(p []byte) (int, error) { return 0, io.ErrUnexpectedEOF }
|
|
|
|
func (b bigBuffer) Write(p []byte) (int, error) { return 0, io.ErrShortBuffer }
|
|
|
|
func (b bigBuffer) Reset() {}
|
|
|
|
func TestBigList(t *testing.T) {
|
|
l := List([]Buffer{bigBuffer{}, bigBuffer{}})
|
|
if l.Len() != math.MaxInt64 {
|
|
t.Errorf("expected list to be max-size: %d", l.Len())
|
|
}
|
|
}
|
|
|
|
func TestBigMulti(t *testing.T) {
|
|
single := NewMulti(bigBuffer{})
|
|
if single.Len() != math.MaxInt64 {
|
|
t.Errorf("expected len to be max-size: %d", single.Len())
|
|
}
|
|
if single.Cap() != math.MaxInt64 {
|
|
t.Errorf("expected cap to be max-size: %d", single.Cap())
|
|
}
|
|
|
|
buf := NewMulti(bigBuffer{}, bigBuffer{})
|
|
if buf.Len() != math.MaxInt64 {
|
|
t.Errorf("expected len to be max-size: %d", buf.Len())
|
|
}
|
|
if buf.Cap() != math.MaxInt64 {
|
|
t.Errorf("expected cap to be max-size: %d", buf.Cap())
|
|
}
|
|
|
|
// test defrag failure
|
|
NewMulti(badBuffer{}, badBuffer{})
|
|
}
|
|
|
|
type badBuffer struct{}
|
|
|
|
func (b badBuffer) Len() int64 { return 1024 }
|
|
|
|
func (b badBuffer) Cap() int64 { return 10 * 1024 }
|
|
|
|
func (b badBuffer) Read(p []byte) (int, error) { return 0, io.ErrUnexpectedEOF }
|
|
|
|
func (b badBuffer) Write(p []byte) (int, error) { return 0, io.ErrShortBuffer }
|
|
|
|
func (b badBuffer) Reset() {}
|
|
|
|
func (b badBuffer) MarshalBinary() ([]byte, error) {
|
|
return nil, errors.New("no data")
|
|
}
|
|
|
|
func TestBadPartition(t *testing.T) {
|
|
p := NewPool(func() Buffer { return badBuffer{} })
|
|
buf := NewPartition(p)
|
|
_, err := buf.Write([]byte("bad write"))
|
|
if err != io.ErrShortBuffer {
|
|
t.Errorf("wrong read error was returned! %v", err)
|
|
}
|
|
|
|
b := make([]byte, 1024)
|
|
_, err = buf.Read(b)
|
|
if err != io.ErrUnexpectedEOF {
|
|
t.Errorf("wrong write error was returned! %v", err)
|
|
}
|
|
}
|
|
|
|
type fakeFile struct {
|
|
name string
|
|
}
|
|
|
|
func (f *fakeFile) Name() string {
|
|
return f.name
|
|
}
|
|
|
|
func (f *fakeFile) Stat() (fi os.FileInfo, err error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (f *fakeFile) ReadAt(p []byte, off int64) (int, error) {
|
|
return 0, io.EOF
|
|
}
|
|
|
|
func (f *fakeFile) WriteAt(p []byte, off int64) (int, error) {
|
|
return 0, io.ErrShortWrite
|
|
}
|
|
|
|
func (f *fakeFile) Close() error { return nil }
|
|
|
|
func TestBadGobFile(t *testing.T) {
|
|
b := NewFile(10, &fakeFile{name: "test"})
|
|
b2 := NewFile(10, &fakeFile{name: "test2"})
|
|
b3 := NewMulti(b, b2)
|
|
buf := bytes.NewBuffer(nil)
|
|
enc := gob.NewEncoder(buf)
|
|
if err := enc.Encode(&b3); err != nil {
|
|
t.Error(err)
|
|
}
|
|
var buffer Buffer
|
|
dec := gob.NewDecoder(buf)
|
|
if err := dec.Decode(&buffer); err == nil {
|
|
t.Error("expected an error here, file does not exist")
|
|
}
|
|
}
|
|
|
|
func TestBadGobFile2(t *testing.T) {
|
|
b := New(10)
|
|
b2 := NewFile(10, &fakeFile{name: "test2"})
|
|
b3 := NewMulti(b, b2)
|
|
buf := bytes.NewBuffer(nil)
|
|
enc := gob.NewEncoder(buf)
|
|
if err := enc.Encode(&b3); err != nil {
|
|
t.Error(err)
|
|
}
|
|
var buffer Buffer
|
|
dec := gob.NewDecoder(buf)
|
|
if err := dec.Decode(&buffer); err == nil {
|
|
t.Error("expected an error here, file does not exist")
|
|
}
|
|
}
|
|
|
|
func TestBadMultiGob(t *testing.T) {
|
|
var b Buffer = badBuffer{}
|
|
var b2 Buffer = badBuffer{}
|
|
var b3 Buffer = New(10)
|
|
b4 := NewMulti(b, b3)
|
|
b5 := NewMulti(b3, b2)
|
|
|
|
enc := gob.NewEncoder(ioutil.Discard)
|
|
if err := enc.Encode(&b4); err == nil {
|
|
t.Error("expected an error here, bad buffer can't be gobbed")
|
|
}
|
|
if err := enc.Encode(&b5); err == nil {
|
|
t.Error("expected an error here, bad buffer can't be gobbed")
|
|
}
|
|
}
|
|
|
|
func TestSwapAt(t *testing.T) {
|
|
buf := NewSwapAt(New(5), New(10))
|
|
buf.WriteAt([]byte("hey"), 0)
|
|
data := make([]byte, 10)
|
|
n, _ := buf.ReadAt(data, 0)
|
|
if string(data[:n]) != "hey" {
|
|
t.Error("expected hey got", string(data[:n]))
|
|
}
|
|
buf.WriteAt([]byte("hey"), 3)
|
|
n, _ = buf.ReadAt(data, 1)
|
|
if string(data[:n]) != "eyhey" {
|
|
t.Error("expected eyhey got", string(data[:n]))
|
|
}
|
|
buf.WriteAt([]byte("hey"), 5)
|
|
n, _ = buf.ReadAt(data, 1)
|
|
if string(data[:n]) != "eyhehey" {
|
|
t.Error("expected eyhehey got", string(data[:n]))
|
|
}
|
|
}
|
|
|
|
func TestSwap(t *testing.T) {
|
|
defer func() {
|
|
recover()
|
|
}()
|
|
buf := NewSwap(New(5), New(10))
|
|
if buf.Len() != 0 {
|
|
t.Error("buffer should start empty got", buf.Len())
|
|
}
|
|
if buf.Cap() != 10 {
|
|
t.Error("cap should be second buffer size (10) got", buf.Cap())
|
|
}
|
|
io.WriteString(buf, "hey")
|
|
data, _ := ioutil.ReadAll(buf)
|
|
if string(data) != "hey" {
|
|
t.Error("expected hey got", string(data))
|
|
}
|
|
io.WriteString(buf, "hey")
|
|
io.WriteString(buf, "hey")
|
|
io.WriteString(buf, "hey")
|
|
data, _ = ioutil.ReadAll(buf)
|
|
if string(data) != "heyheyhey" {
|
|
t.Error("expected heyheyhey got", string(data))
|
|
}
|
|
io.WriteString(buf, "hey")
|
|
if buf.Len() != 3 {
|
|
t.Error("should have data")
|
|
}
|
|
buf.Reset()
|
|
if buf.Len() != 0 {
|
|
t.Error("should be empty")
|
|
}
|
|
|
|
runPerfectSeries(t, NewSwap(New(512), New(1024)))
|
|
|
|
NewSwap(New(1), New(0))
|
|
t.Error("expected panic")
|
|
}
|
|
|
|
func TestPanicReadAt(t *testing.T) {
|
|
defer func() {
|
|
recover()
|
|
}()
|
|
buf := toBufferAt(New(5))
|
|
buf.ReadAt(nil, 0)
|
|
t.Error("expected a panic!")
|
|
}
|
|
|
|
func TestPanicWriteAt(t *testing.T) {
|
|
defer func() {
|
|
recover()
|
|
}()
|
|
buf := toBufferAt(New(5))
|
|
buf.WriteAt(nil, 0)
|
|
t.Error("expected a panic!")
|
|
}
|
|
|
|
type badFile struct{}
|
|
|
|
func (b badFile) Name() string { return "" }
|
|
func (b badFile) Stat() (os.FileInfo, error) { return nil, errors.New("unsupported") }
|
|
func (b badFile) ReadAt(p []byte, off int64) (int, error) { return 0, nil }
|
|
func (b badFile) WriteAt(p []byte, off int64) (int, error) { return len(p), nil }
|
|
func (b badFile) Close() error { return nil }
|
|
|
|
func TestWrapioBreakout(t *testing.T) {
|
|
buf := NewFile(10, badFile{})
|
|
io.WriteString(buf, "hello world")
|
|
if _, err := ioutil.ReadAll(buf); err != io.ErrNoProgress {
|
|
t.Error("expected no progress to be made")
|
|
t.FailNow()
|
|
}
|
|
}
|
|
|
|
func TestListAt(t *testing.T) {
|
|
mem := New(10)
|
|
ory := New(10)
|
|
mem.Write([]byte("Hello"))
|
|
ory.Write([]byte("world"))
|
|
|
|
buf := ListAt([]BufferAt{mem, ory})
|
|
if buf.Len() != 10 {
|
|
t.Errorf("incorrect sum of lengths")
|
|
}
|
|
if buf.Cap() != 20 {
|
|
t.Errorf("incorrect sum of caps")
|
|
}
|
|
|
|
buf.Reset()
|
|
if buf.Len() != 0 {
|
|
t.Errorf("buffer should be empty")
|
|
}
|
|
}
|
|
|
|
func TestPoolAt(t *testing.T) {
|
|
pool := NewPoolAt(func() BufferAt { return New(10) })
|
|
buf, err := pool.Get()
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
buf.Write([]byte("hello world"))
|
|
pool.Put(buf)
|
|
}
|
|
|
|
func TestMemPoolAt(t *testing.T) {
|
|
p := NewMemPoolAt(10)
|
|
poolAtTest(p, t)
|
|
|
|
b := bytes.NewBuffer(nil)
|
|
enc := gob.NewEncoder(b)
|
|
if err := enc.Encode(&p); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
var pool PoolAt
|
|
dec := gob.NewDecoder(b)
|
|
if err := dec.Decode(&pool); err != nil {
|
|
t.Error(err)
|
|
}
|
|
poolAtTest(pool, t)
|
|
}
|
|
|
|
func poolAtTest(pool PoolAt, t *testing.T) {
|
|
buf, err := pool.Get()
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if n, err := buf.Write([]byte("hello world")); n != 10 {
|
|
t.Errorf("wrote incorrect amount")
|
|
} else if err == nil {
|
|
t.Errorf("should have been a shortwrite error here")
|
|
}
|
|
pool.Put(buf)
|
|
if buf.Len() > 0 {
|
|
t.Errorf("should have emptied the buffer")
|
|
}
|
|
}
|
|
|
|
func TestPartitionAt(t *testing.T) {
|
|
buf := NewPartitionAt(NewMemPoolAt(5))
|
|
buf.Write([]byte("Hello World"))
|
|
data := make([]byte, 12)
|
|
n, _ := buf.Read(data)
|
|
if !bytes.Equal(data[:n], []byte("Hello World")) {
|
|
t.Error("Read Failed. " + string(data[:n]))
|
|
}
|
|
|
|
checkCap(t, buf, math.MaxInt64)
|
|
runPerfectSeries(t, buf)
|
|
}
|
|
|
|
// TestPartitionAt2 tests ability to read at various offsets from buffer previously written.
|
|
func TestPartitionAt2(t *testing.T) {
|
|
buf := NewPartitionAt(NewMemPoolAt(5))
|
|
buf.Write([]byte("Hello World"))
|
|
data := make([]byte, 2)
|
|
n, _ := buf.ReadAt(data, 2)
|
|
if !bytes.Equal(data[:n], []byte("ll")) {
|
|
t.Error("Read Failed. " + string(data[:n]))
|
|
}
|
|
n, _ = buf.ReadAt(data, 4)
|
|
if !bytes.Equal(data[:n], []byte("o ")) {
|
|
t.Error("Read Failed. " + string(data[:n]))
|
|
}
|
|
n, _ = buf.ReadAt(data, 10)
|
|
if !bytes.Equal(data[:n], []byte("d")) {
|
|
t.Error("Read Failed. " + string(data[:n]))
|
|
}
|
|
n, _ = buf.ReadAt(data, 100)
|
|
if !bytes.Equal(data[:n], []byte{}) {
|
|
t.Error("Read Failed. " + string(data[:n]))
|
|
}
|
|
|
|
buf.Reset()
|
|
checkCap(t, buf, math.MaxInt64)
|
|
runPerfectSeries(t, buf)
|
|
}
|
|
|
|
// TestPartitionAt3 tests ability to overwrite buffer previously written.
|
|
func TestPartitionAt3(t *testing.T) {
|
|
buf := NewPartitionAt(NewMemPoolAt(5))
|
|
buf.Write(make([]byte, 15, 15)) // allocates 3 membuffers
|
|
buf.WriteAt([]byte("hey"), 0)
|
|
data := make([]byte, 10)
|
|
data = data[:3]
|
|
buf.ReadAt(data, 0)
|
|
if string(data) != "hey" {
|
|
t.Error("expected hey got", string(data))
|
|
}
|
|
buf.WriteAt([]byte("hey"), 3)
|
|
data = data[:5]
|
|
buf.ReadAt(data, 1)
|
|
if string(data) != "eyhey" {
|
|
t.Error("expected eyhey got", string(data))
|
|
}
|
|
buf.WriteAt([]byte("hey"), 5)
|
|
data = data[:7]
|
|
buf.ReadAt(data, 1)
|
|
if string(data) != "eyhehey" {
|
|
t.Error("expected eyhehey got", string(data))
|
|
}
|
|
}
|