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+`}) }