From 237ae8f542812f3677e6934538e7116daa8380f4 Mon Sep 17 00:00:00 2001 From: ccamel Date: Mon, 23 Sep 2024 11:24:45 +0200 Subject: [PATCH] test(vm): add test for Backtrack of Death scenario --- interpreter_test.go | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/interpreter_test.go b/interpreter_test.go index 3472493..fc7c1fa 100644 --- a/interpreter_test.go +++ b/interpreter_test.go @@ -5,13 +5,14 @@ import ( "context" "errors" "fmt" - "github.com/ichiban/prolog/engine" - "github.com/stretchr/testify/assert" "io" "os" "regexp" "testing" "time" + + "github.com/ichiban/prolog/engine" + "github.com/stretchr/testify/assert" ) func TestNew(t *testing.T) { @@ -1184,6 +1185,42 @@ next(N) :- retract(count(X)), N is X + 1, asserta(count(N)). }) } +func TestInterpreter_Bombing(t *testing.T) { + const callLimit = 25 + limitHooker := func(nbCall *int) engine.HookFunc { + return func(opcode engine.Opcode, operand engine.Term, env *engine.Env) error { + if opcode == engine.OpCall { + *nbCall++ + if *nbCall > callLimit { + return engine.ResourceError(engine.NewAtom("calls"), env) + } + } + return nil + } + } + + t.Run("💣 recursion of death", func(t *testing.T) { + nbCalls := 0 + t.Run("create vm", func(t *testing.T) { + i := New(nil, nil) + assert.NotNil(t, i) + i.InstallHook(limitHooker(&nbCalls)) + + t.Run("execute program", func(t *testing.T) { + assert.NoError(t, i.Exec("recursionOfDeath :- recursionOfDeath.")) + + t.Run("💥", func(t *testing.T) { + sol := i.QuerySolutionContext(context.Background(), `recursionOfDeath.`) + + assert.Nil(t, sol.sols) + assert.EqualError(t, sol.Err(), "error(resource_error(calls),recursionOfDeath/0)") + }) + }) + }) + }) + +} + func TestInterpreter_QuerySolution(t *testing.T) { var i Interpreter assert.NoError(t, i.Exec(`