gigaparsec/state_test.go

105 lines
3.5 KiB
Go
Raw Normal View History

2024-09-27 15:29:27 +00:00
package gigaparsec_test
2024-09-03 19:55:32 +00:00
import (
"bytes"
"io"
"testing"
2024-09-27 15:29:27 +00:00
"git.codemonkeysoftware.net/b/gigaparsec"
ptest "git.codemonkeysoftware.net/b/gigaparsec/test"
pgen "git.codemonkeysoftware.net/b/gigaparsec/test/generator"
2024-09-03 19:55:32 +00:00
"github.com/shoenig/test"
"github.com/shoenig/test/must"
"pgregory.net/rapid"
)
2024-09-27 15:29:27 +00:00
func TestState(t *testing.T) {
t.Run("state reads the same position every time", rapid.MakeCheck(func(t *rapid.T) {
2024-09-03 19:55:32 +00:00
data := rapid.SliceOfN(rapid.Byte(), 1, 100).Draw(t, "data")
dst := pgen.SliceOfNZero[byte](0, len(data)-1).Draw(t, "dst")
2024-09-03 19:55:32 +00:00
expected := data[:len(dst)]
2024-09-27 15:29:27 +00:00
st := gigaparsec.MakeState(bytes.NewReader(data))
2024-09-03 19:55:32 +00:00
2024-09-27 15:29:27 +00:00
_, next, err := st.Read(dst)
2024-09-03 19:55:32 +00:00
must.NoError(t, err)
must.SliceEqOp(t, expected, dst)
next.Read(dst)
2024-09-27 15:29:27 +00:00
_, _, err = st.Read(dst)
2024-09-03 19:55:32 +00:00
must.NoError(t, err)
must.SliceEqOp(t, expected, dst)
}))
t.Run("Read returns io.EOF iff it overruns source", rapid.MakeCheck(func(t *rapid.T) {
data := rapid.SliceOfN(rapid.Byte(), 0, 100).Draw(t, "data")
dst := pgen.SliceOfNZero[byte](0, 200).Draw(t, "dst")
2024-09-27 15:29:27 +00:00
st := gigaparsec.MakeState(bytes.NewReader(data))
2024-09-03 19:55:32 +00:00
2024-09-27 15:29:27 +00:00
n, _, err := st.Read(dst)
2024-09-03 19:55:32 +00:00
t.Logf("n=%d", n)
must.EqOp(t, min(len(data), len(dst)), int(n))
2024-09-27 15:29:27 +00:00
if len(dst) > len(data) || st.Pos() == uint64(len(data)) {
2024-09-03 19:55:32 +00:00
must.ErrorIs(t, err, io.EOF)
} else {
must.NoError(t, err)
}
}))
2024-09-27 15:29:27 +00:00
t.Run("next state reads next input", rapid.MakeCheck(func(t *rapid.T) {
2024-09-03 19:55:32 +00:00
const maxLen = 100
data := rapid.SliceOfN(rapid.Byte(), 1, maxLen).Draw(t, "data")
2024-09-11 20:52:27 +00:00
skip := rapid.IntRange(0, len(data)-1).Draw(t, "skip")
2024-09-27 15:29:27 +00:00
st := gigaparsec.MakeState(bytes.NewReader(data))
2024-09-03 19:55:32 +00:00
2024-09-27 15:29:27 +00:00
_, next, err := st.Read(make([]byte, skip))
2024-09-03 19:55:32 +00:00
must.NoError(t, err)
must.EqOp(t, skip, int(next.Pos()))
dst := make([]byte, maxLen)
n, _, _ := next.Read(dst)
must.SliceEqOp(t, data[skip:skip+int(n)], dst[:n])
}))
2024-09-27 15:29:27 +00:00
t.Run("Read returns io.EOF if n is less than requested", rapid.MakeCheck(func(t *rapid.T) {
2024-09-03 19:55:32 +00:00
data := rapid.SliceOfN(rapid.Byte(), 0, 100).Draw(t, "data")
2024-09-27 15:29:27 +00:00
st := gigaparsec.MakeState(bytes.NewReader(data))
2024-09-03 19:55:32 +00:00
2024-09-27 15:29:27 +00:00
n, _, err := st.Read(make([]byte, len(data)+1))
2024-09-03 19:55:32 +00:00
test.ErrorIs(t, err, io.EOF)
test.EqOp(t, len(data), int(n))
}))
2024-09-27 15:29:27 +00:00
t.Run("At sets state position", rapid.MakeCheck(func(t *rapid.T) {
2024-09-08 15:17:29 +00:00
data := rapid.SliceOfN(rapid.Byte(), 1, 100).Draw(t, "data")
pos := rapid.Uint64Range(0, uint64(len(data)-1)).Draw(t, "pos")
2024-09-27 15:29:27 +00:00
st := gigaparsec.MakeState(bytes.NewReader(data)).At(pos)
2024-09-08 15:17:29 +00:00
dst := make([]byte, 1)
2024-09-27 15:29:27 +00:00
n, _, err := st.Read(dst)
2024-09-08 15:17:29 +00:00
test.EqOp(t, 1, n)
test.NoError(t, err)
test.EqOp(t, data[pos], dst[0])
}))
2024-09-11 20:52:27 +00:00
t.Run("Pos returns correct position after At", rapid.MakeCheck(func(t *rapid.T) {
var data []byte
pos := rapid.Uint64().Draw(t, "pos")
2024-09-27 15:29:27 +00:00
st := gigaparsec.MakeState(bytes.NewReader(data)).At(pos)
test.EqOp(t, pos, st.Pos())
2024-09-11 20:52:27 +00:00
}))
t.Run("Pos returns correct position after Read", rapid.MakeCheck(func(t *rapid.T) {
const maxLen = 100
data := rapid.SliceOfN(rapid.Byte(), 1, maxLen).Draw(t, "data")
skip := rapid.Uint64Range(0, uint64(len(data)-1)).Draw(t, "skip")
2024-09-27 15:29:27 +00:00
st := gigaparsec.MakeState(bytes.NewReader(data))
2024-09-11 20:52:27 +00:00
2024-09-27 15:29:27 +00:00
_, next, err := st.Read(make([]byte, skip))
2024-09-11 20:52:27 +00:00
must.NoError(t, err)
test.EqOp(t, skip, next.Pos())
}))
t.Run("Read returns an error if the ReaderAt fails", rapid.MakeCheck(func(t *rapid.T) {
expectedErr := pgen.Error().Draw(t, "expectedErr")
startPos := rapid.Uint64().Draw(t, "startPos")
dst := pgen.SliceOfNZero[byte](0, 100).Draw(t, "dst")
2024-09-27 15:29:27 +00:00
st := gigaparsec.MakeState(ptest.ErrReaderAt(expectedErr)).At(startPos)
n, next, err := st.Read(dst)
test.ErrorIs(t, err, expectedErr)
test.EqOp(t, startPos, next.Pos())
test.Zero(t, n)
}))
2024-09-03 19:55:32 +00:00
}