mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-03 20:27:35 +03:00
An io.Reader can read into the buffer and return the io.EOF in the same call. In fact, that's how the quic.Stream is implemented. In that case, we shouldn't return an error from quicvarint.Read, otherwise the caller won't be able to parse a varint sent just before a stream was closed.
115 lines
2.5 KiB
Go
115 lines
2.5 KiB
Go
package quicvarint
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
|
|
. "github.com/onsi/ginkgo"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
type nopReader struct{}
|
|
|
|
func (r *nopReader) Read(_ []byte) (int, error) {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
|
|
var _ io.Reader = &nopReader{}
|
|
|
|
type nopWriter struct{}
|
|
|
|
func (r *nopWriter) Write(_ []byte) (int, error) {
|
|
return 0, io.ErrShortBuffer
|
|
}
|
|
|
|
// eofReader is a reader that returns data and the io.EOF at the same time in the last Read call
|
|
type eofReader struct {
|
|
Data []byte
|
|
pos int
|
|
}
|
|
|
|
func (r *eofReader) Read(b []byte) (int, error) {
|
|
n := copy(b, r.Data[r.pos:])
|
|
r.pos += n
|
|
if r.pos >= len(r.Data) {
|
|
return n, io.EOF
|
|
}
|
|
return n, nil
|
|
}
|
|
|
|
var _ io.Writer = &nopWriter{}
|
|
|
|
var _ = Describe("Varint I/O", func() {
|
|
Context("Reader", func() {
|
|
Context("NewReader", func() {
|
|
It("passes through a Reader unchanged", func() {
|
|
b := bytes.NewReader([]byte{0})
|
|
r := NewReader(b)
|
|
Expect(r).To(Equal(b))
|
|
})
|
|
|
|
It("wraps an io.Reader", func() {
|
|
n := &nopReader{}
|
|
r := NewReader(n)
|
|
Expect(r).ToNot(Equal(n))
|
|
})
|
|
})
|
|
|
|
It("returns an error when reading from an underlying io.Reader fails", func() {
|
|
r := NewReader(&nopReader{})
|
|
val, err := r.ReadByte()
|
|
Expect(err).To(Equal(io.ErrUnexpectedEOF))
|
|
Expect(val).To(Equal(byte(0)))
|
|
})
|
|
|
|
Context("EOF handling", func() {
|
|
It("eofReader works correctly", func() {
|
|
r := &eofReader{Data: []byte("foobar")}
|
|
b := make([]byte, 3)
|
|
n, err := r.Read(b)
|
|
Expect(n).To(Equal(3))
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(string(b)).To(Equal("foo"))
|
|
n, err = r.Read(b)
|
|
Expect(n).To(Equal(3))
|
|
Expect(err).To(MatchError(io.EOF))
|
|
Expect(string(b)).To(Equal("bar"))
|
|
n, err = r.Read(b)
|
|
Expect(err).To(MatchError(io.EOF))
|
|
Expect(n).To(BeZero())
|
|
})
|
|
|
|
It("correctly handles io.EOF", func() {
|
|
buf := &bytes.Buffer{}
|
|
Write(buf, 1337)
|
|
|
|
r := NewReader(&eofReader{Data: buf.Bytes()})
|
|
n, err := Read(r)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(n).To(BeEquivalentTo(1337))
|
|
})
|
|
})
|
|
})
|
|
|
|
Context("Writer", func() {
|
|
Context("NewWriter", func() {
|
|
It("passes through a Writer unchanged", func() {
|
|
b := &bytes.Buffer{}
|
|
w := NewWriter(b)
|
|
Expect(w).To(Equal(b))
|
|
})
|
|
|
|
It("wraps an io.Writer", func() {
|
|
n := &nopWriter{}
|
|
w := NewWriter(n)
|
|
Expect(w).ToNot(Equal(n))
|
|
})
|
|
})
|
|
|
|
It("returns an error when writing to an underlying io.Writer fails", func() {
|
|
w := NewWriter(&nopWriter{})
|
|
err := w.WriteByte(0)
|
|
Expect(err).To(Equal(io.ErrShortBuffer))
|
|
})
|
|
})
|
|
})
|