Commit c8fa7dcc authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

bytes, strings: fix Reader WriteTo return value on 0 bytes copied

Fixes #4421

R=golang-dev, dave, minux.ma, mchaten, rsc
CC=golang-dev
https://golang.org/cl/6855083
parent 1fbe3090
...@@ -125,7 +125,7 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) { ...@@ -125,7 +125,7 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) {
func (r *Reader) WriteTo(w io.Writer) (n int64, err error) { func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
r.prevRune = -1 r.prevRune = -1
if r.i >= len(r.s) { if r.i >= len(r.s) {
return 0, io.EOF return 0, nil
} }
b := r.s[r.i:] b := r.s[r.i:]
m, err := w.Write(b) m, err := w.Write(b)
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
. "bytes" . "bytes"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"os" "os"
"testing" "testing"
) )
...@@ -88,16 +89,20 @@ func TestReaderAt(t *testing.T) { ...@@ -88,16 +89,20 @@ func TestReaderAt(t *testing.T) {
} }
func TestReaderWriteTo(t *testing.T) { func TestReaderWriteTo(t *testing.T) {
for i := 3; i < 30; i += 3 { for i := 0; i < 30; i += 3 {
s := data[:len(data)/i] var l int
r := NewReader(testBytes[:len(testBytes)/i]) if i > 0 {
l = len(data) / i
}
s := data[:l]
r := NewReader(testBytes[:l])
var b Buffer var b Buffer
n, err := r.WriteTo(&b) n, err := r.WriteTo(&b)
if expect := int64(len(s)); n != expect { if expect := int64(len(s)); n != expect {
t.Errorf("got %v; want %v", n, expect) t.Errorf("got %v; want %v", n, expect)
} }
if err != nil { if err != nil {
t.Errorf("got error = %v; want nil", err) t.Errorf("for length %d: got error = %v; want nil", l, err)
} }
if b.String() != s { if b.String() != s {
t.Errorf("got string %q; want %q", b.String(), s) t.Errorf("got string %q; want %q", b.String(), s)
...@@ -107,3 +112,26 @@ func TestReaderWriteTo(t *testing.T) { ...@@ -107,3 +112,26 @@ func TestReaderWriteTo(t *testing.T) {
} }
} }
} }
// verify that copying from an empty reader always has the same results,
// regardless of the presence of a WriteTo method.
func TestReaderCopyNothing(t *testing.T) {
type nErr struct {
n int64
err error
}
type justReader struct {
io.Reader
}
type justWriter struct {
io.Writer
}
discard := justWriter{ioutil.Discard} // hide ReadFrom
var with, withOut nErr
with.n, with.err = io.Copy(discard, NewReader(nil))
withOut.n, withOut.err = io.Copy(discard, justReader{NewReader(nil)})
if with != withOut {
t.Errorf("behavior differs: with = %#v; without: %#v", with, withOut)
}
}
...@@ -124,7 +124,7 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) { ...@@ -124,7 +124,7 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) {
func (r *Reader) WriteTo(w io.Writer) (n int64, err error) { func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
r.prevRune = -1 r.prevRune = -1
if r.i >= len(r.s) { if r.i >= len(r.s) {
return 0, io.EOF return 0, nil
} }
s := r.s[r.i:] s := r.s[r.i:]
m, err := io.WriteString(w, s) m, err := io.WriteString(w, s)
......
...@@ -90,7 +90,7 @@ func TestReaderAt(t *testing.T) { ...@@ -90,7 +90,7 @@ func TestReaderAt(t *testing.T) {
func TestWriteTo(t *testing.T) { func TestWriteTo(t *testing.T) {
const str = "0123456789" const str = "0123456789"
for i := 0; i < len(str); i++ { for i := 0; i <= len(str); i++ {
s := str[i:] s := str[i:]
r := strings.NewReader(s) r := strings.NewReader(s)
var b bytes.Buffer var b bytes.Buffer
...@@ -99,7 +99,7 @@ func TestWriteTo(t *testing.T) { ...@@ -99,7 +99,7 @@ func TestWriteTo(t *testing.T) {
t.Errorf("got %v; want %v", n, expect) t.Errorf("got %v; want %v", n, expect)
} }
if err != nil { if err != nil {
t.Errorf("got error = %v; want nil", err) t.Errorf("for length %d: got error = %v; want nil", len(s), err)
} }
if b.String() != s { if b.String() != s {
t.Errorf("got string %q; want %q", b.String(), s) t.Errorf("got string %q; want %q", b.String(), s)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment