]> Cypherpunks repositories - gostls13.git/commitdiff
add io.ByteReader.
authorRuss Cox <rsc@golang.org>
Mon, 18 May 2009 20:31:56 +0000 (13:31 -0700)
committerRuss Cox <rsc@golang.org>
Mon, 18 May 2009 20:31:56 +0000 (13:31 -0700)
add testing/iotest package.
make bufio return error on short write.

R=r
DELTA=423  (208 added, 154 deleted, 61 changed)
OCL=28997
CL=28999

src/lib/Makefile
src/lib/bufio/bufio.go
src/lib/bufio/bufio_test.go
src/lib/io/bytebuffer.go
src/lib/io/io.go
src/lib/testing/iotest/Makefile [new file with mode: 0644]
src/lib/testing/iotest/reader.go [new file with mode: 0644]

index 9aaa71e822580fa73b4e31f86e7dbf57a20f81f0..8c605cb880361b0515fdf2d3bb12ffe709fc7e5e 100644 (file)
@@ -45,6 +45,7 @@ DIRS=\
        tabwriter\
        template\
        testing\
+       testing/iotest\
        time\
        unicode\
        utf8\
@@ -115,6 +116,7 @@ nuke: nuke.dirs
 
 bignum.install: fmt.install
 bufio.install: io.install os.install
+crypto/aes.install: os.install
 exec.install: os.install strings.install
 exvar.install: fmt.install http.install log.install strconv.install sync.install
 flag.install: fmt.install os.install strconv.install
@@ -123,7 +125,7 @@ path.install: io.install
 once.install: sync.install
 strings.install: utf8.install
 testing.install: flag.install fmt.install runtime.install
-
+testing/iotest.install: io.install os.install
 fmt.install: io.install reflect.install strconv.install
 GODEPS=fmt.install io.install once.install regexp.install sort.install \
        strconv.install strings.install unicode.install utf8.install container/vector.install
index 3b4aeb820226cf7e7e343d95779580dfa5632434..7bfbb089f7215f5c4bda284710bbb4e07106fa72 100644 (file)
@@ -421,21 +421,17 @@ func (b *Writer) Flush() os.Error {
        if b.err != nil {
                return b.err
        }
-       n := 0;
-       for n < b.n {
-               m, e := b.wr.Write(b.buf[n:b.n]);
-               n += m;
-               if m == 0 && e == nil {
-                       e = io.ErrShortWrite
-               }
-               if e != nil {
-                       if n < b.n {
-                               copySlice(b.buf[0:b.n-n], b.buf[n:b.n])
-                       }
-                       b.n -= n;
-                       b.err = e;
-                       return e
+       n, e := b.wr.Write(b.buf[0:b.n]);
+       if n < b.n && e == nil {
+               e = io.ErrShortWrite;
+       }
+       if e != nil {
+               if n > 0 && n < b.n {
+                       copySlice(b.buf[0:b.n-n], b.buf[n:b.n])
                }
+               b.n -= n;
+               b.err = e;
+               return e
        }
        b.n = 0;
        return nil
@@ -505,14 +501,14 @@ func (b *Writer) WriteByte(c byte) os.Error {
 
 // buffered input and output
 
-// ReadWriter stores (a pointer to) a Reader and a Writer.
+// ReadWriter stores pointers to a Reader and a Writer.
 // It implements io.ReadWriter.
 type ReadWriter struct {
        *Reader;
        *Writer;
 }
 
-// NewReadWriter allocates a new ReadWriter holding r and w.
+// NewReadWriter allocates a new ReadWriter that dispatches to r and w.
 func NewReadWriter(r *Reader, w *Writer) *ReadWriter {
        return &ReadWriter{r, w}
 }
index 240a6d0373443c34d832fc7e3ec40e84b36f2e13..6e5135df782c135949ab46eeab2473ebee92f160 100644 (file)
@@ -10,61 +10,9 @@ import (
        "io";
        "os";
        "testing";
+       "testing/iotest";
 )
 
-// Should be in language!
-func copy(p []byte, q []byte) {
-       for i := 0; i < len(p); i++ {
-               p[i] = q[i]
-       }
-}
-
-// Reads from p.
-type byteReader struct {
-       p []byte
-}
-
-func newByteReader(p []byte) io.Reader {
-       b := new(byteReader);
-       b.p = p;
-       return b
-}
-
-func (b *byteReader) Read(p []byte) (int, os.Error) {
-       n := len(p);
-       if n > len(b.p) {
-               n = len(b.p)
-       }
-       copy(p[0:n], b.p[0:n]);
-       b.p = b.p[n:len(b.p)];
-       return n, nil
-}
-
-
-// Reads from p but only returns half of what you asked for.
-type halfByteReader struct {
-       p []byte
-}
-
-func newHalfByteReader(p []byte) io.Reader {
-       b := new(halfByteReader);
-       b.p = p;
-       return b
-}
-
-func (b *halfByteReader) Read(p []byte) (int, os.Error) {
-       n := len(p)/2;
-       if n == 0 && len(p) > 0 {
-               n = 1
-       }
-       if n > len(b.p) {
-               n = len(b.p)
-       }
-       copy(p[0:n], b.p[0:n]);
-       b.p = b.p[n:len(b.p)];
-       return n, nil
-}
-
 // Reads from a reader and rot13s the result.
 type rot13Reader struct {
        r io.Reader
@@ -82,24 +30,56 @@ func (r13 *rot13Reader) Read(p []byte) (int, os.Error) {
                return n, e
        }
        for i := 0; i < n; i++ {
-               if 'a' <= p[i] && p[i] <= 'z' || 'A' <= p[i] && p[i] <= 'Z' {
-                       if 'a' <= p[i] && p[i] <= 'm' || 'A' <= p[i] && p[i] <= 'M' {
-                               p[i] += 13;
-                       } else {
-                               p[i] -= 13;
-                       }
+               c := p[i] | 0x20;       // lowercase byte
+               if 'a' <= c && c <= 'm' {
+                       p[i] += 13;
+               } else if 'n' <= c && c <= 'z' {
+                       p[i] -= 13;
                }
        }
        return n, nil
 }
 
+// Call ReadByte to accumulate the text of a file
+func readBytes(buf *Reader) string {
+       var b [1000]byte;
+       nb := 0;
+       for {
+               c, e := buf.ReadByte();
+               if e == io.ErrEOF {
+                       break
+               }
+               if e != nil {
+                       panic("Data: "+e.String())
+               }
+               b[nb] = c;
+               nb++;
+       }
+       return string(b[0:nb])
+}
+
+func TestReaderSimple(t *testing.T) {
+       data := io.StringBytes("hello world");
+       b := NewReader(io.NewByteReader(data));
+       if s := readBytes(b); s != "hello world" {
+               t.Errorf("simple hello world test failed: got %q", s);
+       }
+
+       b = NewReader(newRot13Reader(io.NewByteReader(data)));
+       if s := readBytes(b); s != "uryyb jbeyq" {
+               t.Error("rot13 hello world test failed: got %q", s);
+       }
+}
+
+
 type readMaker struct {
        name string;
-       fn func([]byte) io.Reader;
+       fn func(io.Reader) io.Reader;
 }
 var readMakers = []readMaker {
-       readMaker{ "full", func(p []byte) io.Reader { return newByteReader(p) } },
-       readMaker{ "half", func(p []byte) io.Reader { return newHalfByteReader(p) } },
+       readMaker{ "full", func(r io.Reader) io.Reader { return r } },
+       readMaker{ "byte", iotest.OneByteReader },
+       readMaker{ "half", iotest.HalfReader },
 }
 
 // Call ReadLineString (which ends up calling everything else)
@@ -119,25 +99,6 @@ func readLines(b *Reader) string {
        return s
 }
 
-// Call ReadByte to accumulate the text of a file
-func readBytes(buf *Reader) string {
-       var b [1000]byte;
-       nb := 0;
-       for {
-               c, e := buf.ReadByte();
-               if e == io.ErrEOF {
-                       break
-               }
-               if e != nil {
-                       panic("GetBytes: "+e.String())
-               }
-               b[nb] = c;
-               nb++;
-       }
-       // BUG return string(b[0:nb]) ?
-       return string(b[0:nb])
-}
-
 // Call Read to accumulate the text of a file
 func reads(buf *Reader, m int) string {
        var b [1000]byte;
@@ -172,18 +133,6 @@ var bufsizes = []int {
        23, 32, 46, 64, 93, 128, 1024, 4096
 }
 
-func TestReaderSimple(t *testing.T) {
-       b := NewReader(newByteReader(io.StringBytes("hello world")));
-       if s := readBytes(b); s != "hello world" {
-               t.Errorf("simple hello world test failed: got %q", s);
-       }
-
-       b = NewReader(newRot13Reader(newByteReader(io.StringBytes("hello world"))));
-       if s := readBytes(b); s != "uryyb jbeyq" {
-               t.Error("rot13 hello world test failed: got %q", s);
-       }
-}
-
 func TestReader(t *testing.T) {
        var texts [31]string;
        str := "";
@@ -204,7 +153,7 @@ func TestReader(t *testing.T) {
                                        readmaker := readMakers[i];
                                        bufreader := bufreaders[j];
                                        bufsize := bufsizes[k];
-                                       read := readmaker.fn(textbytes);
+                                       read := readmaker.fn(io.NewByteReader(textbytes));
                                        buf, e := NewReaderSize(read, bufsize);
                                        s := bufreader.fn(buf);
                                        if s != text {
@@ -217,122 +166,92 @@ func TestReader(t *testing.T) {
        }
 }
 
-type writeBuffer interface {
-       Write(p []byte) (int, os.Error);
-       GetBytes() []byte
-}
-
-// Accumulates bytes into a byte array.
-type byteWriter struct {
-       p []byte;
-       n int
-}
-
-func newByteWriter() writeBuffer {
-       return new(byteWriter)
-}
+func TestWriter(t *testing.T) {
+       var data [8192]byte;
 
-func (w *byteWriter) Write(p []byte) (int, os.Error) {
-       if w.p == nil {
-               w.p = make([]byte, len(p)+100)
-       } else if w.n + len(p) >= len(w.p) {
-               newp := make([]byte, len(w.p)*2 + len(p));
-               copy(newp[0:w.n], w.p[0:w.n]);
-               w.p = newp
+       for i := 0; i < len(data); i++ {
+               data[i] = byte(' '+ i%('~'-' '));
        }
-       copy(w.p[w.n:w.n+len(p)], p);
-       w.n += len(p);
-       return len(p), nil
-}
-
-func (w *byteWriter) GetBytes() []byte {
-       return w.p[0:w.n]
-}
+       w := new(io.ByteBuffer);
+       for i := 0; i < len(bufsizes); i++ {
+               for j := 0; j < len(bufsizes); j++ {
+                       nwrite := bufsizes[i];
+                       bs := bufsizes[j];
+
+                       // Write nwrite bytes using buffer size bs.
+                       // Check that the right amount makes it out
+                       // and that the data is correct.
+
+                       w.Reset();
+                       buf, e := NewWriterSize(w, bs);
+                       context := fmt.Sprintf("nwrite=%d bufsize=%d", nwrite, bs);
+                       if e != nil {
+                               t.Errorf("%s: NewWriterSize %d: %v", context, bs, e);
+                               continue;
+                       }
+                       n, e1 := buf.Write(data[0:nwrite]);
+                       if e1 != nil || n != nwrite {
+                               t.Errorf("%s: buf.Write %d = %d, %v", context, nwrite, n, e1);
+                               continue;
+                       }
+                       if e = buf.Flush(); e != nil {
+                               t.Errorf("%s: buf.Flush = %v", context, e);
+                       }
 
-// Accumulates bytes written into a byte array
-// but Write only takes half of what you give it.
-// TODO: Could toss this -- Write() is not supposed to do that.
-type halfByteWriter struct {
-       bw writeBuffer
+                       written := w.Data();
+                       if len(written) != nwrite {
+                               t.Errorf("%s: %d bytes written", context, len(written));
+                       }
+                       for l := 0; l < len(written); l++ {
+                               if written[i] != data[i] {
+                                       t.Errorf("%s: wrong bytes written");
+                                       t.Errorf("want=%s", data[0:len(written)]);
+                                       t.Errorf("have=%s", written);
+                               }
+                       }
+               }
+       }
 }
 
-func newHalfByteWriter() writeBuffer {
-       w := new(halfByteWriter);
-       w.bw = newByteWriter();
-       return w
-}
+// Check that write errors are returned properly.
 
-func (w *halfByteWriter) Write(p []byte) (int, os.Error) {
-       n := (len(p)+1) / 2;
-       // BUG return w.bw.Write(p[0:n])
-       r, e := w.bw.Write(p[0:n]);
-       return r, e
+type errorWriterTest struct {
+       n, m int;
+       err os.Error;
+       expect os.Error;
 }
 
-func (w *halfByteWriter) GetBytes() []byte {
-       return w.bw.GetBytes()
+func (w errorWriterTest) Write(p []byte) (int, os.Error) {
+       return len(p)*w.n/w.m, w.err;
 }
 
-type writeMaker struct {
-       name string;
-       fn func()writeBuffer;
+var errorWriterTests = []errorWriterTest {
+       errorWriterTest{ 0, 1, nil, io.ErrShortWrite },
+       errorWriterTest{ 1, 2, nil, io.ErrShortWrite },
+       errorWriterTest{ 1, 1, nil, nil },
+       errorWriterTest{ 0, 1, os.EPIPE, os.EPIPE },
+       errorWriterTest{ 1, 2, os.EPIPE, os.EPIPE },
+       errorWriterTest{ 1, 1, os.EPIPE, os.EPIPE },
 }
-func TestWriter(t *testing.T) {
-       var data [8192]byte;
-
-       var writers = []writeMaker {
-               writeMaker{ "full", newByteWriter },
-               writeMaker{ "half", newHalfByteWriter },
-       };
-
-       for i := 0; i < len(data); i++ {
-               data[i] = byte(' '+ i%('~'-' '));
-       }
-       for i := 0; i < len(bufsizes); i++ {
-               for j := 0; j < len(bufsizes); j++ {
-                       for k := 0; k < len(writers); k++ {
-                               nwrite := bufsizes[i];
-                               bs := bufsizes[j];
 
-                               // Write nwrite bytes using buffer size bs.
-                               // Check that the right amount makes it out
-                               // and that the data is correct.
-
-                               write := writers[k].fn();
-                               buf, e := NewWriterSize(write, bs);
-                               context := fmt.Sprintf("write=%s nwrite=%d bufsize=%d", writers[k].name, nwrite, bs);
-                               if e != nil {
-                                       t.Errorf("%s: NewWriterSize %d: %v", context, bs, e);
-                                       continue;
-                               }
-                               n, e1 := buf.Write(data[0:nwrite]);
-                               if e1 != nil || n != nwrite {
-                                       t.Errorf("%s: buf.Write %d = %d, %v", context, nwrite, n, e1);
-                                       continue;
-                               }
-                               if e = buf.Flush(); e != nil {
-                                       t.Errorf("%s: buf.Flush = %v", context, e);
-                               }
-
-                               written := write.GetBytes();
-                               if len(written) != nwrite {
-                                       t.Errorf("%s: %d bytes written", context, len(written));
-                               }
-                               for l := 0; l < len(written); l++ {
-                                       if written[i] != data[i] {
-                                               t.Errorf("%s: wrong bytes written");
-                                               t.Errorf("want=%s", data[0:len(written)]);
-                                               t.Errorf("have=%s", written);
-                                       }
-                               }
-                       }
+func TestWriteErrors(t *testing.T) {
+       for i, w := range errorWriterTests {
+               buf := NewWriter(w);
+               n, e := buf.Write(io.StringBytes("hello world"));
+               if e != nil {
+                       t.Errorf("Write hello to %v: %v", w, e);
+                       continue;
+               }
+               e = buf.Flush();
+               if e != w.expect {
+                       t.Errorf("Flush %v: got %v, wanted %v", w, e, w.expect);
                }
        }
 }
 
 func TestNewReaderSizeIdempotent(t *testing.T) {
        const BufSize = 1000;
-       b, err := NewReaderSize(newByteReader(io.StringBytes("hello world")), BufSize);
+       b, err := NewReaderSize(io.NewByteReader(io.StringBytes("hello world")), BufSize);
        if err != nil {
                t.Error("NewReaderSize create fail", err);
        }
@@ -356,7 +275,7 @@ func TestNewReaderSizeIdempotent(t *testing.T) {
 
 func TestNewWriterSizeIdempotent(t *testing.T) {
        const BufSize = 1000;
-       b, err := NewWriterSize(newByteWriter(), BufSize);
+       b, err := NewWriterSize(new(io.ByteBuffer), BufSize);
        if err != nil {
                t.Error("NewWriterSize create fail", err);
        }
index c862818fd777b4c7e4eb78c058bc296091728b01..921ddb17aead963a105d11ea3d0bb2523cb7889e 100644 (file)
@@ -42,13 +42,17 @@ func (b *ByteBuffer) Len() int {
 // Truncate discards all but the first n unread bytes from the buffer.
 // It is an error to call b.Truncate(n) with n > b.Len().
 func (b *ByteBuffer) Truncate(n int) {
+       if n == 0 {
+               // Reuse buffer space.
+               b.off = 0;
+       }
        b.buf = b.buf[0 : b.off + n];
 }
 
 // Reset resets the buffer so it has no content.
 // b.Reset() is the same as b.Truncate(0).
 func (b *ByteBuffer) Reset() {
-       b.buf = b.buf[0 : b.off];
+       b.Truncate(0);
 }
 
 // Write appends the contents of p to the buffer.  The return
index 70c82d56293de8f330e6f7d31e474ee2eeeb6634..91b6ffd8b9b6eb003ec802a5f5c8c55e87348d49 100644 (file)
@@ -185,3 +185,29 @@ func Copy(src Reader, dst Writer) (written int64, err os.Error) {
        }
        return written, err
 }
+
+// A ByteReader satisfies Reads by consuming data from a slice of bytes.
+// Clients can call NewByteReader to create one or wrap pointers
+// to their own slices: r := ByteReader{&data}.
+type ByteReader struct {
+       Data *[]byte
+}
+
+func (r ByteReader) Read(p []byte) (int, os.Error) {
+       n := len(p);
+       b := r.Data;
+       if n > len(b) {
+               n = len(b);
+       }
+       for i := 0; i < n; i++ {
+               p[i] = b[i];
+       }
+       *b = b[n:len(b)];
+       return n, nil;
+}
+
+// NewByteReader returns a new ByteReader reading from data.
+func NewByteReader(data []byte) ByteReader {
+       return ByteReader{ &data };
+}
+
diff --git a/src/lib/testing/iotest/Makefile b/src/lib/testing/iotest/Makefile
new file mode 100644 (file)
index 0000000..5bfa513
--- /dev/null
@@ -0,0 +1,68 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# DO NOT EDIT.  Automatically generated by gobuild.
+# gobuild -m >Makefile
+
+D=/testing/
+
+O_arm=5
+O_amd64=6
+O_386=8
+OS=568vq
+
+O=$(O_$(GOARCH))
+GC=$(O)g -I_obj
+CC=$(O)c -FVw
+AS=$(O)a
+AR=6ar
+
+default: packages
+
+clean:
+       rm -rf *.[$(OS)] *.a [$(OS)].out _obj
+
+test: packages
+       gotest
+
+coverage: packages
+       gotest
+       6cov -g `pwd` | grep -v '_test\.go:'
+
+%.$O: %.go
+       $(GC) $*.go
+
+%.$O: %.c
+       $(CC) $*.c
+
+%.$O: %.s
+       $(AS) $*.s
+
+O1=\
+       reader.$O\
+
+
+phases: a1
+_obj$D/iotest.a: phases
+
+a1: $(O1)
+       $(AR) grc _obj$D/iotest.a reader.$O
+       rm -f $(O1)
+
+
+newpkg: clean
+       mkdir -p _obj$D
+       $(AR) grc _obj$D/iotest.a
+
+$(O1): newpkg
+$(O2): a1
+
+nuke: clean
+       rm -f $(GOROOT)/pkg$D/iotest.a
+
+packages: _obj$D/iotest.a
+
+install: packages
+       test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg$D
+       cp _obj$D/iotest.a $(GOROOT)/pkg$D/iotest.a
diff --git a/src/lib/testing/iotest/reader.go b/src/lib/testing/iotest/reader.go
new file mode 100644 (file)
index 0000000..0bb8633
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The iotest package implements Readers and Writers
+// useful only for testing.
+package iotest
+
+import (
+       "io";
+       "os";
+)
+
+type oneByteReader struct {
+       r io.Reader;
+}
+
+func (r *oneByteReader) Read(p []byte) (int, os.Error) {
+       if len(p) == 0 {
+               return 0, nil;
+       }
+       return r.r.Read(p[0:1]);
+}
+
+// OneByteReader returns a Reader that implements
+// each non-empty Read by reading one byte from r.
+func OneByteReader(r io.Reader) io.Reader {
+       return &oneByteReader{r};
+}
+
+type halfReader struct {
+       r io.Reader;
+}
+
+func (r *halfReader) Read(p []byte) (int, os.Error) {
+       return r.r.Read(p[0:(len(p)+1)/2]);
+}
+
+// HalfReader returns a Reader that implements Read
+// by reading half as many requested bytes from r.
+func HalfReader(r io.Reader) io.Reader {
+       return &halfReader{r};
+}
+