add io.ByteReader.
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
diff --git a/src/lib/bufio/bufio_test.go b/src/lib/bufio/bufio_test.go
index 240a6d0..6e5135d 100644
--- a/src/lib/bufio/bufio_test.go
+++ b/src/lib/bufio/bufio_test.go
@@ -10,61 +10,9 @@
 	"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 @@
 		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 @@
 	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 @@
 	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 @@
 					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 @@
 	}
 }
 
-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 (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
-	}
-	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]
-}
-
-// 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
-}
-
-func newHalfByteWriter() writeBuffer {
-	w := new(halfByteWriter);
-	w.bw = newByteWriter();
-	return w
-}
-
-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
-}
-
-func (w *halfByteWriter) GetBytes() []byte {
-	return w.bw.GetBytes()
-}
-
-type writeMaker struct {
-	name string;
-	fn func()writeBuffer;
-}
 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%('~'-' '));
 	}
+	w := new(io.ByteBuffer);
 	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];
+			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 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);
-				}
+			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);
+			}
 
-				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);
-					}
+			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);
 				}
 			}
 		}
 	}
 }
 
+// Check that write errors are returned properly.
+
+type errorWriterTest struct {
+	n, m int;
+	err os.Error;
+	expect os.Error;
+}
+
+func (w errorWriterTest) Write(p []byte) (int, os.Error) {
+	return len(p)*w.n/w.m, w.err;
+}
+
+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 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 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);
 	}