Added chicken and egg recursion detection

This commit is contained in:
2020-02-06 17:50:14 +01:00
parent afc1e22949
commit 7481b458e1
16 changed files with 358 additions and 77 deletions
+10 -4
View File
@@ -1,5 +1,5 @@
from core.builtin_concepts import BuiltinConcepts
from core.concept import PROPERTIES_TO_SERIALIZE
from core.concept import PROPERTIES_TO_SERIALIZE, Concept
from sdp.sheerkaDataProvider import SheerkaDataProvider
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -80,12 +80,10 @@ class TestSheerkaCreateNewConcept(TestUsingMemoryBasedSheerka):
sheerka.cache_by_key = {} # reset the cache
loaded = sheerka.get(concept.key)
assert loaded is not None
assert loaded == concept
# I can also get it by its id
loaded = sheerka.sdp.get(sheerka.CONCEPTS_BY_ID_ENTRY, concept.id)
assert loaded is not None
assert loaded == concept
def test_i_can_get_a_concept_by_its_id(self):
@@ -96,7 +94,6 @@ class TestSheerkaCreateNewConcept(TestUsingMemoryBasedSheerka):
sheerka.cache_by_key = {} # reset the cache
loaded = sheerka.get_by_id(concept.id)
assert loaded is not None
assert loaded == concept
def test_i_can_get_list_of_concept_when_same_key_when_no_cache(self):
@@ -178,3 +175,12 @@ class TestSheerkaCreateNewConcept(TestUsingMemoryBasedSheerka):
result = sheerka.get(concept1.key, "wrong id")
assert sheerka.isinstance(result, BuiltinConcepts.UNKNOWN_CONCEPT)
def test_concept_that_references_itself_is_correctly_created(self):
sheerka = self.get_sheerka()
concept = Concept("foo", body="foo")
res = sheerka.create_new_concept(self.get_context(sheerka), concept)
assert res.status
+89 -1
View File
@@ -1,6 +1,6 @@
import pytest
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, ParserResultConcept
from core.concept import Concept, simplec, DoNotResolve, ConceptParts, Property
from core.concept import Concept, simplec, DoNotResolve, ConceptParts, Property, InfiniteRecursionResolved
from parsers.PythonParser import PythonNode
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
@@ -369,3 +369,91 @@ class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept)
assert sheerka.isinstance(evaluated, BuiltinConcepts.WHERE_CLAUSE_FAILED)
assert evaluated.body == concept
def test_i_can_detect_infinite_recursion_with_numeric_constant(self):
sheerka = self.get_sheerka()
one_str = Concept("one", body="1")
one_digit = Concept("1", body="one")
sheerka.add_in_cache(one_str)
sheerka.add_in_cache(one_digit)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), one_digit)
assert evaluated.key == one_digit.key
assert evaluated.body == InfiniteRecursionResolved(1)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), one_str)
assert evaluated.key == one_str.key
assert evaluated.body == InfiniteRecursionResolved(1)
def test_i_can_detect_infinite_recursion_with_boolean_constant(self):
sheerka = self.get_sheerka()
true_str = Concept("true", body="True")
true_bool = Concept("True", body="true")
sheerka.add_in_cache(true_str)
sheerka.add_in_cache(true_bool)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), true_str)
assert evaluated.key == true_str.key
assert evaluated.body == InfiniteRecursionResolved(True)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), true_bool)
assert evaluated.key == true_bool.key
assert evaluated.body == InfiniteRecursionResolved(True)
def test_i_can_detect_infinite_recursion_with_constant_with_more_concepts(self):
sheerka = self.get_sheerka()
c1 = sheerka.add_in_cache(Concept("one", body="1"))
c2 = sheerka.add_in_cache(Concept("1", body="2"))
c3 = sheerka.add_in_cache(Concept("2", body="3"))
c4 = sheerka.add_in_cache(Concept("3", body="one"))
for concept in (c1, c2, c3, c4):
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), concept)
assert evaluated.key == concept.key
assert evaluated.body == InfiniteRecursionResolved(3)
def test_i_can_detect_infinite_recursion_when_no_constant(self):
sheerka = self.get_sheerka()
foo = sheerka.add_in_cache(Concept("foo", body="bar"))
bar = sheerka.add_in_cache(Concept("bar", body="baz"))
baz = sheerka.add_in_cache(Concept("baz", body="qux"))
qux = sheerka.add_in_cache(Concept("qux", body="foo"))
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), foo)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
assert evaluated.body == {foo, bar, baz, qux}
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), bar)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
assert evaluated.body == {foo, bar, baz, qux}
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), baz)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
assert evaluated.body == {foo, bar, baz, qux}
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), qux)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
assert evaluated.body == {foo, bar, baz, qux}
def test_i_can_detect_auto_recursion(self):
sheerka = self.get_sheerka()
foo = sheerka.add_in_cache(Concept("foo", body="foo"))
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), foo)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
assert evaluated.body == {foo}
def test_i_can_manage_auto_recursion_when_constant(self):
sheerka = self.get_sheerka()
one = Concept("1", body="1")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka), one)
assert evaluated.key == one.key
assert evaluated.body == 1
+38
View File
@@ -242,3 +242,41 @@ class TestSheerka(TestUsingFileBasedSheerka):
# only test a random one, it will be the same for the others
sheerka = self.get_sheerka()
assert not sheerka.is_success(sheerka.new(BuiltinConcepts.TOO_MANY_SUCCESS))
def test_cache_is_updated_after_get(self):
sheerka = self.get_sheerka()
# updated when by_key returns one element
sheerka.create_new_concept(self.get_context(sheerka), Concept("foo", body="1"))
sheerka.reset_cache()
sheerka.get("foo")
assert "foo" in sheerka.cache_by_key
assert "1001" in sheerka.cache_by_id
# updated when by_key returns two elements
sheerka.create_new_concept(self.get_context(sheerka), Concept("foo", body="2"))
sheerka.reset_cache()
sheerka.get("foo")
assert "foo" in sheerka.cache_by_key
assert "1001" in sheerka.cache_by_id
assert "1002" in sheerka.cache_by_id
# updated when by_id
sheerka.reset_cache()
sheerka.get_by_id("1001")
assert "1001" in sheerka.cache_by_id
assert "foo" not in sheerka.cache_by_key # cache_by_key not updated as "1001" is not the only one
def test_i_can_get_by_key_several_times(self):
sheerka = self.get_sheerka()
sheerka.create_new_concept(self.get_context(sheerka), Concept("foo", body="1"))
sheerka.create_new_concept(self.get_context(sheerka), Concept("foo", body="2"))
sheerka.reset_cache()
sheerka.get("foo", "1001") # only one element requested. But the cache must be updated with two elements
# let's check it
concepts = sheerka.get("foo")
assert len(concepts) == 2
assert concepts[0].id == "1001"
assert concepts[1].id == "1002"