1// Copyright 2022 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package slicewriter
6
7import (
8	"io"
9	"testing"
10)
11
12func TestSliceWriter(t *testing.T) {
13
14	sleq := func(t *testing.T, got []byte, want []byte) {
15		t.Helper()
16		if len(got) != len(want) {
17			t.Fatalf("bad length got %d want %d", len(got), len(want))
18		}
19		for i := range got {
20			if got[i] != want[i] {
21				t.Fatalf("bad read at %d got %d want %d", i, got[i], want[i])
22			}
23		}
24	}
25
26	wf := func(t *testing.T, ws *WriteSeeker, p []byte) {
27		t.Helper()
28		nw, werr := ws.Write(p)
29		if werr != nil {
30			t.Fatalf("unexpected write error: %v", werr)
31		}
32		if nw != len(p) {
33			t.Fatalf("wrong amount written want %d got %d", len(p), nw)
34		}
35	}
36
37	rf := func(t *testing.T, ws *WriteSeeker, p []byte) {
38		t.Helper()
39		b := make([]byte, len(p))
40		nr, rerr := ws.Read(b)
41		if rerr != nil {
42			t.Fatalf("unexpected read error: %v", rerr)
43		}
44		if nr != len(p) {
45			t.Fatalf("wrong amount read want %d got %d", len(p), nr)
46		}
47		sleq(t, b, p)
48	}
49
50	sk := func(t *testing.T, ws *WriteSeeker, offset int64, whence int) int64 {
51		t.Helper()
52		off, err := ws.Seek(offset, whence)
53		if err != nil {
54			t.Fatalf("unexpected seek error: %v", err)
55		}
56		return off
57	}
58
59	wp1 := []byte{1, 2}
60	ws := &WriteSeeker{}
61
62	// write some stuff
63	wf(t, ws, wp1)
64	// check that BytesWritten returns what we wrote.
65	sleq(t, ws.BytesWritten(), wp1)
66	// offset is at end of slice, so reading should return zero bytes.
67	rf(t, ws, []byte{})
68
69	// write some more stuff
70	wp2 := []byte{7, 8, 9}
71	wf(t, ws, wp2)
72	// check that BytesWritten returns what we expect.
73	wpex := []byte{1, 2, 7, 8, 9}
74	sleq(t, ws.BytesWritten(), wpex)
75	rf(t, ws, []byte{})
76
77	// seeks and reads.
78	sk(t, ws, 1, io.SeekStart)
79	rf(t, ws, []byte{2, 7})
80	sk(t, ws, -2, io.SeekCurrent)
81	rf(t, ws, []byte{2, 7})
82	sk(t, ws, -4, io.SeekEnd)
83	rf(t, ws, []byte{2, 7})
84	off := sk(t, ws, 0, io.SeekEnd)
85	sk(t, ws, off, io.SeekStart)
86
87	// seek back and overwrite
88	sk(t, ws, 1, io.SeekStart)
89	wf(t, ws, []byte{9, 11})
90	wpex = []byte{1, 9, 11, 8, 9}
91	sleq(t, ws.BytesWritten(), wpex)
92
93	// seeks on empty writer.
94	ws2 := &WriteSeeker{}
95	sk(t, ws2, 0, io.SeekStart)
96	sk(t, ws2, 0, io.SeekCurrent)
97	sk(t, ws2, 0, io.SeekEnd)
98
99	// check for seek errors.
100	_, err := ws.Seek(-1, io.SeekStart)
101	if err == nil {
102		t.Fatalf("expected error on invalid -1 seek")
103	}
104	_, err = ws.Seek(int64(len(ws.BytesWritten())+1), io.SeekStart)
105	if err == nil {
106		t.Fatalf("expected error on invalid %d seek", len(ws.BytesWritten()))
107	}
108
109	ws.Seek(0, io.SeekStart)
110	_, err = ws.Seek(-1, io.SeekCurrent)
111	if err == nil {
112		t.Fatalf("expected error on invalid -1 seek")
113	}
114	_, err = ws.Seek(int64(len(ws.BytesWritten())+1), io.SeekCurrent)
115	if err == nil {
116		t.Fatalf("expected error on invalid %d seek", len(ws.BytesWritten()))
117	}
118
119	_, err = ws.Seek(1, io.SeekEnd)
120	if err == nil {
121		t.Fatalf("expected error on invalid 1 seek")
122	}
123	bsamt := int64(-1*len(ws.BytesWritten()) - 1)
124	_, err = ws.Seek(bsamt, io.SeekEnd)
125	if err == nil {
126		t.Fatalf("expected error on invalid %d seek", bsamt)
127	}
128
129	// bad seek mode
130	_, err = ws.Seek(-1, io.SeekStart+9)
131	if err == nil {
132		t.Fatalf("expected error on invalid seek mode")
133	}
134}
135