aboutsummaryrefslogtreecommitdiffstats
path: root/oae2_test.go
diff options
context:
space:
mode:
authorRose Hogenson <rosehogenson@posteo.net>2026-01-03 08:22:51 -0800
committerRose Hogenson <rosehogenson@posteo.net>2026-01-03 11:17:07 -0800
commit2aecb1f4f570849ace353c577436f63a9f4de209 (patch)
tree36c0b7af6ae69578ad65a993056c5c2e36e36ca9 /oae2_test.go
parent32efe0766ed06964e72bfe622a5146c9ff324ab0 (diff)
downloadoae2-2aecb1f4f570849ace353c577436f63a9f4de209.tar.zst
Add support for seeking within a stream
Oh God what have I done
Diffstat (limited to 'oae2_test.go')
-rw-r--r--oae2_test.go194
1 files changed, 194 insertions, 0 deletions
diff --git a/oae2_test.go b/oae2_test.go
index 96b83af..e326ef2 100644
--- a/oae2_test.go
+++ b/oae2_test.go
@@ -55,6 +55,74 @@ func TestReadFromWriteTo(t *testing.T) {
}
}
+func TestReader_Seek(t *testing.T) {
+ t.Parallel()
+ const (
+ msg = "Hello World!"
+ key = "asdf"
+ blockSize = 1
+ )
+ for _, tc := range []struct {
+ desc string
+ offset int64
+ whence int
+ wantOffset int64
+ wantMsg string
+ }{{
+ desc: "SeekStart",
+ offset: 6,
+ whence: io.SeekStart,
+ wantOffset: 6,
+ wantMsg: "World!",
+ }, {
+ desc: "SeekEnd",
+ offset: -6,
+ whence: io.SeekEnd,
+ wantOffset: 6,
+ wantMsg: "World!",
+ }, {
+ desc: "SeekEndOffsetZero",
+ offset: 0,
+ whence: io.SeekEnd,
+ wantOffset: 12,
+ wantMsg: "",
+ }, {
+ desc: "SeekCurrent",
+ offset: 6,
+ whence: io.SeekCurrent,
+ wantOffset: 6,
+ wantMsg: "World!",
+ }} {
+ t.Run(tc.desc, func(t *testing.T) {
+ t.Parallel()
+
+ buf := new(bytes.Buffer)
+ w := NewWriter(buf, []byte(key), blockSize)
+ if _, err := io.WriteString(w, msg); err != nil {
+ t.Fatalf("Writer.Write failed: %s", err)
+ }
+ if err := w.Close(); err != nil {
+ t.Fatalf("Writer.Close failed: %s", err)
+ }
+ r := NewReader(bytes.NewReader(buf.Bytes()), []byte(key), blockSize)
+ n, err := r.Seek(tc.offset, tc.whence)
+ if err != nil {
+ t.Fatalf("Reader.Seek(%d, %d) failed: %s", tc.offset, tc.whence, err)
+ }
+ if n != tc.wantOffset {
+ t.Errorf("Reader.Seek(%d, %d) = %d, want %d", tc.offset, tc.whence, n, tc.wantOffset)
+ }
+ got, err := io.ReadAll(r)
+ if err != nil {
+ t.Fatalf("Reader.Read failed: %s", err)
+ }
+ if string(got) != tc.wantMsg {
+ t.Errorf("Incorrect message after Seek: got %q, want %q", got, tc.wantMsg)
+ }
+ })
+ }
+}
+
func FuzzRoundTrip(f *testing.F) {
f.Add(1, []byte("Hello World!"))
f.Fuzz(func(t *testing.T, segmentSize int, msg []byte) {
@@ -118,3 +186,129 @@ func FuzzReadFromWriteTo(f *testing.F) {
}
})
}
+
+func FuzzSeekStart(f *testing.F) {
+ f.Add(1, []byte("Hello World!"), 6)
+ f.Add(30, []byte("000000"), 6)
+ f.Fuzz(func(t *testing.T, segmentSize int, msg []byte, offset int) {
+ const password = "asdf"
+
+ if segmentSize <= 0 || offset > len(msg) {
+ return
+ }
+ buf := new(bytes.Buffer)
+ w := NewWriter(buf, []byte(password), segmentSize)
+ if _, err := w.Write(msg); err != nil {
+ t.Fatalf("Writer.Write(%q) failed: %s", msg, err)
+ }
+ if err := w.Close(); err != nil {
+ t.Fatalf("Writer.Close failed: %s", err)
+ }
+ r := NewReader(bytes.NewReader(buf.Bytes()), []byte(password), segmentSize)
+ n, err := r.Seek(int64(offset), io.SeekStart)
+ if offset < 0 {
+ if err == nil {
+ t.Errorf("Seek(%d, io.SeekStart) succeeded, want error", offset)
+ }
+ return
+ }
+ if err != nil {
+ t.Fatalf("Seek(%d, io.SeekStart) failed: %s", offset, err)
+ }
+ if n != int64(offset) {
+ t.Errorf("Seek(%d, io.SeekStart) = %d, want %d", offset, n, offset)
+ }
+ got, err := io.ReadAll(r)
+ if err != nil {
+ t.Fatalf("Reader.Read failed: %s", err)
+ }
+ if !bytes.Equal(got, msg[offset:]) {
+ t.Errorf("Message after seek is %q, want %q", got, msg[offset:])
+ }
+ })
+}
+
+func FuzzSeekEnd(f *testing.F) {
+ f.Add(1, []byte("Hello World!"), -6)
+ f.Fuzz(func(t *testing.T, segmentSize int, msg []byte, offset int) {
+ const password = "asdf"
+
+ if segmentSize <= 0 || offset > 0 {
+ return
+ }
+ buf := new(bytes.Buffer)
+ w := NewWriter(buf, []byte(password), segmentSize)
+ if _, err := w.Write(msg); err != nil {
+ t.Fatalf("Writer.Write(%q) failed: %s", msg, err)
+ }
+ if err := w.Close(); err != nil {
+ t.Fatalf("Writer.Close failed: %s", err)
+ }
+ r := NewReader(bytes.NewReader(buf.Bytes()), []byte(password), segmentSize)
+ n, err := r.Seek(int64(offset), io.SeekEnd)
+ if len(msg)+offset < 0 {
+ if err == nil {
+ t.Errorf("Seek(%d, io.SeekEnd) succeeded, want error", offset)
+ }
+ return
+ }
+ if err != nil {
+ t.Fatalf("Seek(%d, io.SeekEnd) failed: %s", offset, err)
+ }
+ if n != int64(len(msg)+offset) {
+ t.Errorf("Seek(%d, io.SeekEnd) = %d, want %d", offset, n, offset)
+ }
+ got, err := io.ReadAll(r)
+ if err != nil {
+ t.Fatalf("Reader.Read failed: %s", err)
+ }
+ if !bytes.Equal(got, msg[len(msg)+offset:]) {
+ t.Errorf("Message after seek is %q, want %q", got, msg[offset:])
+ }
+ })
+}
+
+func FuzzSeekCurrent(f *testing.F) {
+ f.Add(1, []byte("Hello World!"), 3, 3)
+ f.Add(1, []byte("000000"), 3, 3)
+ f.Add(1, []byte("000"), 3, -3)
+ f.Fuzz(func(t *testing.T, segmentSize int, msg []byte, offset1, offset2 int) {
+ const password = "asdf"
+
+ if segmentSize <= 0 || offset1 < 0 || offset1 > len(msg) || offset1+offset2 > len(msg) {
+ return
+ }
+ buf := new(bytes.Buffer)
+ w := NewWriter(buf, []byte(password), segmentSize)
+ if _, err := w.Write(msg); err != nil {
+ t.Fatalf("Writer.Write(%q) failed: %s", msg, err)
+ }
+ if err := w.Close(); err != nil {
+ t.Fatalf("Writer.Close failed: %s", err)
+ }
+ r := NewReader(bytes.NewReader(buf.Bytes()), []byte(password), segmentSize)
+ if _, err := io.ReadFull(r, make([]byte, offset1)); err != nil {
+ t.Fatalf("Reader.Read failed: %s", err)
+ }
+ n, err := r.Seek(int64(offset2), io.SeekCurrent)
+ if offset1+offset2 < 0 {
+ if err == nil {
+ t.Errorf("Seek(%d, io.SeekCurrent) succeeded, want error", offset2)
+ }
+ return
+ }
+ if err != nil {
+ t.Fatalf("Seek(%d, io.SeekCurrent) failed: %s", offset2, err)
+ }
+ if n != int64(offset1+offset2) {
+ t.Errorf("Seek(%d, io.SeekEnd) = %d, want %d", offset2, n, offset1+offset2)
+ }
+ got, err := io.ReadAll(r)
+ if err != nil {
+ t.Fatalf("Reader.Read failed: %s", err)
+ }
+ if !bytes.Equal(got, msg[offset1+offset2:]) {
+ t.Errorf("Message after seek is %q, want %q", got, msg[offset1+offset2:])
+ }
+ })
+}