summaryrefslogtreecommitdiff
path: root/libgo/go/bufio/bufio_test.go
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2012-11-21 07:03:38 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2012-11-21 07:03:38 +0000
commit79a796b7d3db5d100eedfc774954a6b44944363a (patch)
tree72455aea0286937aa08cc141e5efc800e4626577 /libgo/go/bufio/bufio_test.go
parent7224cf54b3af2b931fb83af65f9cfab5c1df814a (diff)
downloadgcc-79a796b7d3db5d100eedfc774954a6b44944363a.tar.gz
libgo: Update to current version of master library.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@193688 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/bufio/bufio_test.go')
-rw-r--r--libgo/go/bufio/bufio_test.go173
1 files changed, 163 insertions, 10 deletions
diff --git a/libgo/go/bufio/bufio_test.go b/libgo/go/bufio/bufio_test.go
index 4e10207efbd..75d9edf8b1c 100644
--- a/libgo/go/bufio/bufio_test.go
+++ b/libgo/go/bufio/bufio_test.go
@@ -763,8 +763,8 @@ func testReadLineNewlines(t *testing.T, input string, expect []readLineResult) {
}
}
-func TestReaderWriteTo(t *testing.T) {
- input := make([]byte, 8192)
+func createTestInput(n int) []byte {
+ input := make([]byte, n)
for i := range input {
// 101 and 251 are arbitrary prime numbers.
// The idea is to create an input sequence
@@ -774,7 +774,12 @@ func TestReaderWriteTo(t *testing.T) {
input[i] ^= byte(i / 101)
}
}
- r := NewReader(bytes.NewBuffer(input))
+ return input
+}
+
+func TestReaderWriteTo(t *testing.T) {
+ input := createTestInput(8192)
+ r := NewReader(onlyReader{bytes.NewBuffer(input)})
w := new(bytes.Buffer)
if n, err := r.WriteTo(w); err != nil || n != int64(len(input)) {
t.Fatalf("r.WriteTo(w) = %d, %v, want %d, nil", n, err, len(input))
@@ -817,12 +822,129 @@ func TestReaderWriteToErrors(t *testing.T) {
}
}
+func TestWriterReadFrom(t *testing.T) {
+ ws := []func(io.Writer) io.Writer{
+ func(w io.Writer) io.Writer { return onlyWriter{w} },
+ func(w io.Writer) io.Writer { return w },
+ }
+
+ rs := []func(io.Reader) io.Reader{
+ iotest.DataErrReader,
+ func(r io.Reader) io.Reader { return r },
+ }
+
+ for ri, rfunc := range rs {
+ for wi, wfunc := range ws {
+ input := createTestInput(8192)
+ b := new(bytes.Buffer)
+ w := NewWriter(wfunc(b))
+ r := rfunc(bytes.NewBuffer(input))
+ if n, err := w.ReadFrom(r); err != nil || n != int64(len(input)) {
+ t.Errorf("ws[%d],rs[%d]: w.ReadFrom(r) = %d, %v, want %d, nil", wi, ri, n, err, len(input))
+ continue
+ }
+ if got, want := b.String(), string(input); got != want {
+ t.Errorf("ws[%d], rs[%d]:\ngot %q\nwant %q\n", wi, ri, got, want)
+ }
+ }
+ }
+}
+
+type errorReaderFromTest struct {
+ rn, wn int
+ rerr, werr error
+ expected error
+}
+
+func (r errorReaderFromTest) Read(p []byte) (int, error) {
+ return len(p) * r.rn, r.rerr
+}
+
+func (w errorReaderFromTest) Write(p []byte) (int, error) {
+ return len(p) * w.wn, w.werr
+}
+
+var errorReaderFromTests = []errorReaderFromTest{
+ {0, 1, io.EOF, nil, nil},
+ {1, 1, io.EOF, nil, nil},
+ {0, 1, io.ErrClosedPipe, nil, io.ErrClosedPipe},
+ {0, 0, io.ErrClosedPipe, io.ErrShortWrite, io.ErrClosedPipe},
+ {1, 0, nil, io.ErrShortWrite, io.ErrShortWrite},
+}
+
+func TestWriterReadFromErrors(t *testing.T) {
+ for i, rw := range errorReaderFromTests {
+ w := NewWriter(rw)
+ if _, err := w.ReadFrom(rw); err != rw.expected {
+ t.Errorf("w.ReadFrom(errorReaderFromTests[%d]) = _, %v, want _,%v", i, err, rw.expected)
+ }
+ }
+}
+
+// TestWriterReadFromCounts tests that using io.Copy to copy into a
+// bufio.Writer does not prematurely flush the buffer. For example, when
+// buffering writes to a network socket, excessive network writes should be
+// avoided.
+func TestWriterReadFromCounts(t *testing.T) {
+ var w0 writeCountingDiscard
+ b0 := NewWriterSize(&w0, 1234)
+ b0.WriteString(strings.Repeat("x", 1000))
+ if w0 != 0 {
+ t.Fatalf("write 1000 'x's: got %d writes, want 0", w0)
+ }
+ b0.WriteString(strings.Repeat("x", 200))
+ if w0 != 0 {
+ t.Fatalf("write 1200 'x's: got %d writes, want 0", w0)
+ }
+ io.Copy(b0, onlyReader{strings.NewReader(strings.Repeat("x", 30))})
+ if w0 != 0 {
+ t.Fatalf("write 1230 'x's: got %d writes, want 0", w0)
+ }
+ io.Copy(b0, onlyReader{strings.NewReader(strings.Repeat("x", 9))})
+ if w0 != 1 {
+ t.Fatalf("write 1239 'x's: got %d writes, want 1", w0)
+ }
+
+ var w1 writeCountingDiscard
+ b1 := NewWriterSize(&w1, 1234)
+ b1.WriteString(strings.Repeat("x", 1200))
+ b1.Flush()
+ if w1 != 1 {
+ t.Fatalf("flush 1200 'x's: got %d writes, want 1", w1)
+ }
+ b1.WriteString(strings.Repeat("x", 89))
+ if w1 != 1 {
+ t.Fatalf("write 1200 + 89 'x's: got %d writes, want 1", w1)
+ }
+ io.Copy(b1, onlyReader{strings.NewReader(strings.Repeat("x", 700))})
+ if w1 != 1 {
+ t.Fatalf("write 1200 + 789 'x's: got %d writes, want 1", w1)
+ }
+ io.Copy(b1, onlyReader{strings.NewReader(strings.Repeat("x", 600))})
+ if w1 != 2 {
+ t.Fatalf("write 1200 + 1389 'x's: got %d writes, want 2", w1)
+ }
+ b1.Flush()
+ if w1 != 3 {
+ t.Fatalf("flush 1200 + 1389 'x's: got %d writes, want 3", w1)
+ }
+}
+
+// A writeCountingDiscard is like ioutil.Discard and counts the number of times
+// Write is called on it.
+type writeCountingDiscard int
+
+func (w *writeCountingDiscard) Write(p []byte) (int, error) {
+ *w++
+ return len(p), nil
+}
+
// An onlyReader only implements io.Reader, no matter what other methods the underlying implementation may have.
type onlyReader struct {
r io.Reader
}
-func (r *onlyReader) Read(b []byte) (int, error) {
+func (r onlyReader) Read(b []byte) (int, error) {
return r.r.Read(b)
}
@@ -831,7 +953,7 @@ type onlyWriter struct {
w io.Writer
}
-func (w *onlyWriter) Write(b []byte) (int, error) {
+func (w onlyWriter) Write(b []byte) (int, error) {
return w.w.Write(b)
}
@@ -840,7 +962,7 @@ func BenchmarkReaderCopyOptimal(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
src := NewReader(bytes.NewBuffer(make([]byte, 8192)))
- dst := &onlyWriter{new(bytes.Buffer)}
+ dst := onlyWriter{new(bytes.Buffer)}
b.StartTimer()
io.Copy(dst, src)
}
@@ -850,8 +972,8 @@ func BenchmarkReaderCopyUnoptimal(b *testing.B) {
// Unoptimal case is where the underlying reader doesn't implement io.WriterTo
for i := 0; i < b.N; i++ {
b.StopTimer()
- src := NewReader(&onlyReader{bytes.NewBuffer(make([]byte, 8192))})
- dst := &onlyWriter{new(bytes.Buffer)}
+ src := NewReader(onlyReader{bytes.NewBuffer(make([]byte, 8192))})
+ dst := onlyWriter{new(bytes.Buffer)}
b.StartTimer()
io.Copy(dst, src)
}
@@ -860,8 +982,39 @@ func BenchmarkReaderCopyUnoptimal(b *testing.B) {
func BenchmarkReaderCopyNoWriteTo(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
- src := &onlyReader{NewReader(bytes.NewBuffer(make([]byte, 8192)))}
- dst := &onlyWriter{new(bytes.Buffer)}
+ src := onlyReader{NewReader(bytes.NewBuffer(make([]byte, 8192)))}
+ dst := onlyWriter{new(bytes.Buffer)}
+ b.StartTimer()
+ io.Copy(dst, src)
+ }
+}
+
+func BenchmarkWriterCopyOptimal(b *testing.B) {
+ // Optimal case is where the underlying writer implements io.ReaderFrom
+ for i := 0; i < b.N; i++ {
+ b.StopTimer()
+ src := onlyReader{bytes.NewBuffer(make([]byte, 8192))}
+ dst := NewWriter(new(bytes.Buffer))
+ b.StartTimer()
+ io.Copy(dst, src)
+ }
+}
+
+func BenchmarkWriterCopyUnoptimal(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ b.StopTimer()
+ src := onlyReader{bytes.NewBuffer(make([]byte, 8192))}
+ dst := NewWriter(onlyWriter{new(bytes.Buffer)})
+ b.StartTimer()
+ io.Copy(dst, src)
+ }
+}
+
+func BenchmarkWriterCopyNoReadFrom(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ b.StopTimer()
+ src := onlyReader{bytes.NewBuffer(make([]byte, 8192))}
+ dst := onlyWriter{NewWriter(new(bytes.Buffer))}
b.StartTimer()
io.Copy(dst, src)
}