// If an EOF happens after reading fewer than min bytes,
// ReadAtLeast returns ErrUnexpectedEOF.
// If min is greater than the length of buf, ReadAtLeast returns ErrShortBuffer.
+// On return, n >= min if and only if err == nil.
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error) {
if len(buf) < min {
return 0, ErrShortBuffer
nn, err = r.Read(buf[n:])
n += nn
}
- if err == EOF {
- if n >= min {
- err = nil
- } else if n > 0 {
- err = ErrUnexpectedEOF
- }
+ if n >= min {
+ err = nil
+ } else if n > 0 && err == EOF {
+ err = ErrUnexpectedEOF
}
return
}
// The error is EOF only if no bytes were read.
// If an EOF happens after reading some but not all the bytes,
// ReadFull returns ErrUnexpectedEOF.
+// On return, n == len(buf) if and only if err == nil.
func ReadFull(r Reader, buf []byte) (n int, err error) {
return ReadAtLeast(r, buf, len(buf))
}
import (
"bytes"
+ "fmt"
. "io"
"strings"
"testing"
testReadAtLeast(t, &rb)
}
-// A version of bytes.Buffer that returns n > 0, EOF on Read
+// A version of bytes.Buffer that returns n > 0, err on Read
// when the input is exhausted.
-type dataAndEOFBuffer struct {
+type dataAndErrorBuffer struct {
+ err error
bytes.Buffer
}
-func (r *dataAndEOFBuffer) Read(p []byte) (n int, err error) {
+func (r *dataAndErrorBuffer) Read(p []byte) (n int, err error) {
n, err = r.Buffer.Read(p)
if n > 0 && r.Buffer.Len() == 0 && err == nil {
- err = EOF
+ err = r.err
}
return
}
func TestReadAtLeastWithDataAndEOF(t *testing.T) {
- var rb dataAndEOFBuffer
+ var rb dataAndErrorBuffer
+ rb.err = EOF
+ testReadAtLeast(t, &rb)
+}
+
+func TestReadAtLeastWithDataAndError(t *testing.T) {
+ var rb dataAndErrorBuffer
+ rb.err = fmt.Errorf("fake error")
testReadAtLeast(t, &rb)
}
}
rb.Write([]byte("4"))
n, err = ReadAtLeast(rb, buf, 2)
- if err != ErrUnexpectedEOF {
- t.Errorf("expected ErrUnexpectedEOF, got %v", err)
+ want := ErrUnexpectedEOF
+ if rb, ok := rb.(*dataAndErrorBuffer); ok && rb.err != EOF {
+ want = rb.err
+ }
+ if err != want {
+ t.Errorf("expected %v, got %v", want, err)
}
if n != 1 {
t.Errorf("expected to have read 1 bytes, got %v", n)