Bring mwc to 100% coverage.

This commit is contained in:
Kyle Isom 2016-04-28 12:42:05 -07:00
parent 80bea5c005
commit f93f662d7e
2 changed files with 142 additions and 10 deletions

View File

@ -4,7 +4,8 @@ import (
"bytes"
"testing"
"github.com/kisom/testio"
"github.com/kisom/goutils/testio"
"github.com/kisom/goutils/assert"
)
func TestMWC(t *testing.T) {
@ -13,15 +14,43 @@ func TestMWC(t *testing.T) {
mwc := MultiWriteCloser(buf1, buf2)
if _, err := mwc.Write([]byte("hello, world")); err != nil {
t.Fatalf("%v", err)
}
_, err := mwc.Write([]byte("hello, world"))
assert.NoErrorT(t, err)
if !bytes.Equal(buf1.Bytes(), buf2.Bytes()) {
t.Fatal("write failed")
}
assert.BoolT(t, bytes.Equal(buf1.Bytes(), buf2.Bytes()), "write failed")
assert.BoolT(t, bytes.Equal(buf1.Bytes(), []byte("hello, world")), "write failed")
if !bytes.Equal(buf1.Bytes(), []byte("hello, world")) {
t.Fatal("writing failed")
}
err = mwc.Close()
assert.NoErrorT(t, err)
}
func TestMWCShort(t *testing.T) {
buf1 := testio.NewBufCloser(nil)
buf2 := testio.NewBufCloser(nil)
buf3 := testio.NewBrokenWriter(5)
buf4 := testio.NewSilentBrokenWriter(5)
mwc := MultiWriteCloser(buf1, buf2, buf3)
defer mwc.Close()
_, err := mwc.Write([]byte("hello, world"))
assert.ErrorT(t, err, "expected a short write error", "but no error occurred")
mwc.Close()
mwc = MultiWriteCloser(buf1, buf2, buf4)
_, err = mwc.Write([]byte("hello, world"))
assert.ErrorT(t, err, "expected a short write error", "but no error occurred")
}
func TestMWCClose(t *testing.T) {
buf1 := testio.NewBufCloser(nil)
buf2 := testio.NewBufCloser(nil)
buf3 := testio.NewBrokenCloser(nil)
mwc := MultiWriteCloser(buf1, buf2, buf3)
_, err := mwc.Write([]byte("hello, world"))
assert.NoErrorT(t, err)
err = mwc.Close()
assert.ErrorT(t, err, "expected broken closer to fail")
}

View File

@ -55,6 +55,59 @@ func (w *BrokenWriter) Reset() {
w.current = 0
}
// Close is provided to satisfy the Closer interface.
func (w *BrokenWriter) Close() error {
w.Reset()
return nil
}
// SilentBrokenWriter implements an io.Writer that fails after a
// certain number of bytes. However, this failure is silent: it just
// reports fewer bytes written than p. It doesn't actually store any
// data, and is used to verify that io.Writer implementations properly
// return errors on short writes.
type SilentBrokenWriter struct {
current, limit int
}
// NewSilentBrokenWriter creates a new SilentBrokenWriter that can store only
// limit bytes.
func NewSilentBrokenWriter(limit int) *SilentBrokenWriter {
return &SilentBrokenWriter{limit: limit}
}
// Write will write the byte slice to the SilentBrokenWriter, failing if the
// maximum number of bytes has been reached.
func (w *SilentBrokenWriter) Write(p []byte) (int, error) {
if (len(p) + w.current) <= w.limit {
w.current += len(p)
} else {
spill := (len(p) + w.current) - w.limit
w.current = w.limit
return len(p) - spill, nil
}
return len(p), nil
}
// Extend increases the byte limit to allow more data to be written.
func (w *SilentBrokenWriter) Extend(n int) {
w.limit += n
}
// Reset clears the limit and bytes in the SilentBrokenWriter. Extend needs
// to be called to allow data to be written.
func (w *SilentBrokenWriter) Reset() {
w.limit = 0
w.current = 0
}
// Close is provided to satisfy the Closer interface.
func (w *SilentBrokenWriter) Close() error {
w.Reset()
return nil
}
// BrokenReadWriter implements a broken reader and writer, backed by a
// bytes.Buffer.
type BrokenReadWriter struct {
@ -259,3 +312,53 @@ func (bc *BufferConn) ReadClient(p []byte) (int, error) {
func (bc *BufferConn) Close() error {
return nil
}
// BrokenCloser is a BufCloser that fails to close.
type BrokenCloser struct {
buf *bytes.Buffer
}
// Write writes the data to the BrokenCloser.
func (buf *BrokenCloser) Write(p []byte) (int, error) {
return buf.buf.Write(p)
}
// Read reads data from the BrokenCloser.
func (buf *BrokenCloser) Read(p []byte) (int, error) {
return buf.buf.Read(p)
}
// Close is a stub function to satisfy the io.Closer interface.
func (buf *BrokenCloser) Close() error {
return errors.New("testio: broken closer is broken")
}
// Reset clears the internal buffer.
func (buf *BrokenCloser) Reset() {
buf.buf.Reset()
}
// Bytes returns the contents of the buffer as a byte slice.
func (buf *BrokenCloser) Bytes() []byte {
return buf.buf.Bytes()
}
// NewBrokenCloser creates and initializes a new BrokenCloser using buf as
// its initial contents. It is intended to prepare a BrokenCloser to read
// existing data. It can also be used to size the internal buffer for
// writing. To do that, buf should have the desired capacity but a
// length of zero.
func NewBrokenCloser(buf []byte) *BrokenCloser {
bc := new(BrokenCloser)
bc.buf = bytes.NewBuffer(buf)
return bc
}
// NewBrokenCloserString creates and initializes a new Buffer using
// string s as its initial contents. It is intended to prepare a
// buffer to read an existing string.
func NewBrokenCloserString(s string) *BrokenCloser {
buf := new(BrokenCloser)
buf.buf = bytes.NewBufferString(s)
return buf
}