Added Try tests

This commit is contained in:
Brandon Dyck 2024-10-17 08:57:45 -06:00
parent abef123f8a
commit bc2f7aa911
2 changed files with 51 additions and 27 deletions

View File

@ -5,7 +5,7 @@ package gigaparsec_test
import ( import (
"bytes" "bytes"
"errors" "errors"
"io" "fmt"
"testing" "testing"
"git.codemonkeysoftware.net/b/gigaparsec" "git.codemonkeysoftware.net/b/gigaparsec"
@ -127,8 +127,32 @@ func TestSatisfy(t *testing.T) {
Todo(t) Todo(t)
} }
func Try(t *testing.T) { func TestTry(t *testing.T) {
Todo(t) type R = ptest.ForcedResult
var cases = []struct{ P, TryP R }{
{P: R{Succeed: false, Consume: false}, TryP: R{Succeed: false, Consume: false}},
{P: R{Succeed: false, Consume: true}, TryP: R{Succeed: false, Consume: false}},
{P: R{Succeed: true, Consume: false}, TryP: R{Succeed: true, Consume: false}},
{P: R{Succeed: true, Consume: true}, TryP: R{Succeed: true, Consume: true}},
}
for _, c := range cases {
t.Run(fmt.Sprintf("%+v", c.P), func(t *testing.T) {
start := gigaparsec.MakeState(gigaparsec.SliceReaderAt[R]{c.P})
result, err := gigaparsec.Try(ptest.ForceResult)(start)
succeeded, _, _ := result.Status()
must.NoError(t, err)
test.EqOp(t, c.TryP.Succeed, succeeded)
test.EqOp(t, c.TryP.Consume, result.Consumed())
})
}
t.Run("fails on error", func(t *testing.T) {
expectedErr := errors.New("it broke")
p := gigaparsec.Try(gigaparsec.Match(byte(0)))
result, err := p(gigaparsec.MakeState(ptest.ErrReaderAt(expectedErr)))
succeeded, _, _ := result.Status()
test.ErrorIs(t, err, expectedErr)
test.False(t, succeeded)
})
} }
func TestLabel(t *testing.T) { func TestLabel(t *testing.T) {
@ -158,39 +182,19 @@ func TestRepeat(t *testing.T) {
} }
})) }))
t.Run("consumes iff at least one application consumes", rapid.MakeCheck(func(t *rapid.T) { t.Run("consumes iff at least one application consumes", rapid.MakeCheck(func(t *rapid.T) {
type Token struct { input := rapid.Map(rapid.SliceOfN(rapid.Just(ptest.ForcedResult{Succeed: true}), 0, 100),
Consume, Succeed bool func(ts []ptest.ForcedResult) []ptest.ForcedResult { return append(ts, ptest.ForcedResult{}) }).Draw(t, "input")
}
// p will succeed and consume based on the values in the parsed token.
var p gigaparsec.Parser[Token, Token] = func(s gigaparsec.State[Token]) (gigaparsec.Result[Token, Token], error) {
buf := make([]Token, 1)
_, next, err := s.Read(buf)
if errors.Is(err, io.EOF) {
return gigaparsec.Fail[Token, Token](false, gigaparsec.MessageEnd(s.Pos())), nil
}
if err != nil {
return gigaparsec.Result[Token, Token]{}, err
}
tok := buf[0]
if tok.Succeed {
return gigaparsec.Succeed(tok.Consume, tok, next, gigaparsec.MessageOK(s.Pos())), nil
} else {
return gigaparsec.Fail[Token, Token](tok.Consume, gigaparsec.MakeMessage(s.Pos(), "false", "true")), nil
}
}
input := rapid.Map(rapid.SliceOfN(rapid.Just(Token{Succeed: true}), 0, 100),
func(ts []Token) []Token { return append(ts, Token{}) }).Draw(t, "input")
consumeAt := rapid.Ptr(rapid.IntRange(0, len(input)-1), true).Draw(t, "consumeAt") consumeAt := rapid.Ptr(rapid.IntRange(0, len(input)-1), true).Draw(t, "consumeAt")
if consumeAt != nil { if consumeAt != nil {
input[*consumeAt].Consume = true input[*consumeAt].Consume = true
} }
shouldConsume := consumeAt != nil shouldConsume := consumeAt != nil
result, err := gigaparsec.Repeat(0, p)(gigaparsec.MakeState(gigaparsec.SliceReaderAt[Token](input))) result, err := gigaparsec.Repeat(0, ptest.ForceResult)(gigaparsec.MakeState(gigaparsec.SliceReaderAt[ptest.ForcedResult](input)))
must.NoError(t, err) must.NoError(t, err)
test.EqOp(t, shouldConsume, result.Consumed()) test.EqOp(t, shouldConsume, result.Consumed())
})) }))
t.Run("does not consume on empty input", func(t *testing.T) { t.Run("does not consume on empty input", func(t *testing.T) {
p := gigaparsec.Repeat(0, gigaparsec.Match(0)) p := gigaparsec.Repeat(0, gigaparsec.Match(0))
result, err := p(gigaparsec.MakeState(gigaparsec.SliceReaderAt[int](nil))) result, err := p(gigaparsec.MakeState(gigaparsec.SliceReaderAt[int](nil)))

View File

@ -4,6 +4,7 @@
package test package test
import ( import (
"errors"
"io" "io"
"git.codemonkeysoftware.net/b/gigaparsec" "git.codemonkeysoftware.net/b/gigaparsec"
@ -34,3 +35,22 @@ func SliceOfN[T any](value T, n int) []T {
} }
return s return s
} }
type ForcedResult struct{ Succeed, Consume bool }
func ForceResult(state gigaparsec.State[ForcedResult]) (gigaparsec.Result[ForcedResult, struct{}], error) {
buf := make([]ForcedResult, 1)
_, next, err := state.Read(buf)
if errors.Is(err, io.EOF) {
return gigaparsec.Fail[ForcedResult, struct{}](false, gigaparsec.MessageEnd(state.Pos())), nil
}
if err != nil {
return gigaparsec.Result[ForcedResult, struct{}]{}, err
}
tok := buf[0]
if tok.Succeed {
return gigaparsec.Succeed(tok.Consume, struct{}{}, next, gigaparsec.MessageOK(state.Pos())), nil
} else {
return gigaparsec.Fail[ForcedResult, struct{}](tok.Consume, gigaparsec.MakeMessage(state.Pos(), "Succeed=false", "Succeed=true")), nil
}
}