go-parsekit/parsehandler_test.go

107 lines
3.3 KiB
Go

package parsekit_test
import (
"testing"
"git.makaay.nl/mauricem/go-parsekit"
)
func TestGivenNilTokenHandler_WhenCallingOn_ParsekitPanics(t *testing.T) {
p := parsekit.NewParser(func(p *parsekit.ParseAPI) {
p.On(nil)
})
RunPanicTest(t, PanicTest{
func() { p.Execute("") },
`ParseHandler bug: tokenHandler argument for On\(\) is nil`})
}
func TestGivenStoppedParser_WhenCallingHandle_ParsekitPanics(t *testing.T) {
otherHandler := func(p *parsekit.ParseAPI) {
panic("This is not the handler you're looking for")
}
p := parsekit.NewParser(func(p *parsekit.ParseAPI) {
p.Stop()
p.Handle(otherHandler)
})
RunPanicTest(t, PanicTest{
func() { p.Execute("") },
`Illegal call to ParseAPI.Handle\(\) from .*ParsekitPanics.func.* at ` +
`.*/parsehandler_test.go:\d+: no calls allowed after ParseAPI.Stop\(\)`})
}
func TestGivenParserWithError_WhenCallingHandle_ParsekitPanics(t *testing.T) {
otherHandler := func(p *parsekit.ParseAPI) {
panic("This is not the handler you're looking for")
}
p := parsekit.NewParser(func(p *parsekit.ParseAPI) {
p.Error("It ends here")
p.Handle(otherHandler)
})
RunPanicTest(t, PanicTest{
func() { p.Execute("") },
`Illegal call to ParseAPI\.Handle\(\) from .*ParsekitPanics\.func2 at ` +
`.*/parsehandler_test\.go:\d+: no calls allowed after ParseAPI\.Error\(\)`})
}
type parserWithLoop struct {
loopCounter int
}
func (l *parserWithLoop) first(p *parsekit.ParseAPI) {
p.On(parsekit.A.ASCII).Accept()
p.Handle(l.second)
}
func (l *parserWithLoop) second(p *parsekit.ParseAPI) {
p.On(parsekit.A.ASCII).Accept()
p.Handle(l.third)
}
func (l *parserWithLoop) third(p *parsekit.ParseAPI) {
if l.loopCounter++; l.loopCounter > 100 {
p.Error("Loop not detected by parsekit")
return
}
p.On(parsekit.A.ASCII).Accept()
p.Handle(l.first)
}
func TestGivenLoopingParserDefinition_ParserPanics(t *testing.T) {
looper := &parserWithLoop{}
parser := parsekit.NewParser(looper.first)
RunPanicTest(t, PanicTest{
func() { parser.Execute("Het houdt niet op, niet vanzelf") },
`Loop detected in parser in .*\(\*parserWithLoop\).second at .*/parsehandler_test\.go:\d+`})
}
// This test incorporates an actual loop bug that I dropped on myself and
// that I could not easily spot in my code. It sounded so logical:
// I want to get chunks of 5 chars from the input, so I simply loop on:
//
// p.On(c.Max(5, a.AnyRune))
//
// The problem here is that Max(5, ...) will also match when there is
// no more input, since Max(5, ---) is actually MinMax(0, 5, ...).
// Therefore the loop will never stop. Solving the loop was simple:
//
// p.On(c.MinMax(1, 5, a.AnyRune))
//
// Now the loop stops when the parser finds no more matching input data.
func TestGivenLoopingParserDefinition2_ParserPanics(t *testing.T) {
parser := parsekit.NewParser(func(p *parsekit.ParseAPI) {
for p.On(c.Max(5, a.AnyRune)).Accept() {
}
p.Stop()
})
RunPanicTest(t, PanicTest{
func() { parser.Execute("This will end soon") },
`Loop detected in parser in .*ParserPanics.* at .*/parsehandler_test.go:\d+`})
}
func TestGivenNullHandler_HandlePanics(t *testing.T) {
parser := parsekit.NewParser(nil)
RunPanicTest(t, PanicTest{
func() { parser.Execute("") },
`ParseAPI.Handle\(\) called with nil input from .*\(\*Parser\).Execute at .*/parsekit\.go:\d+`})
}