Files
Sheerka-Old/tests/core/test_SheerkaEvaluateConcept.py
T
2020-09-21 21:30:38 +02:00

911 lines
38 KiB
Python

import pytest
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, ParserResultConcept
from core.concept import Concept, DoNotResolve, ConceptParts, Property, InfiniteRecursionResolved, CB, NotInit
from core.sheerka.services.SheerkaEvaluateConcept import SheerkaEvaluateConcept
from core.sheerka.services.SheerkaMemory import SheerkaMemory
from parsers.PythonParser import PythonNode
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka):
@pytest.mark.parametrize("body, expected", [
(None, BuiltinConcepts.NOT_INITIALIZED),
("", ""),
("1", 1),
("1+1", 2),
("'one'", "one"),
("'one' + 'two'", "onetwo"),
("True", True),
("1 > 2", False),
])
def test_i_can_evaluate_a_concept_with_simple_body(self, body, expected):
sheerka, context, concept = self.init_concepts(Concept("foo", body=body), eval_body=True)
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.body == expected
assert evaluated.metadata.body == body
assert evaluated.metadata.pre is None
assert evaluated.metadata.post is None
assert evaluated.metadata.where is None
assert evaluated.variables() == {}
assert evaluated.metadata.is_evaluated
assert len(evaluated.values) == 0 if body is None else 1
assert "foo" in sheerka.services[SheerkaMemory.NAME].registration
@pytest.mark.parametrize("expr, expected", [
("", ""),
("1", 1),
("1+1", 2),
("'one'", "one"),
("'one' + 'two'", "onetwo"),
("True", True),
("1 > 2", False),
])
def test_i_can_evaluate_the_other_metadata(self, expr, expected):
"""
I only test PRE, it's the same for the others
:param expr:
:param expected:
:return:
"""
sheerka, context, concept = self.init_concepts(Concept("foo", post=expr))
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.metadata.body is None
assert evaluated.metadata.post == expr
assert evaluated.metadata.pre is None
assert evaluated.metadata.where is None
assert evaluated.get_value(ConceptParts.POST) == expected
assert evaluated.variables() == {}
assert not evaluated.metadata.is_evaluated
assert len(evaluated.values) == 0 if expr is None else 1
@pytest.mark.parametrize("expr, expected", [
(None, NotInit),
("", ""),
("1", 1),
("1+1", 2),
("'one'", "one"),
("'one' + 'two'", "onetwo"),
("True", True),
("1 > 2", False),
])
def test_i_can_evaluate_a_concept_with_prop(self, expr, expected):
sheerka, context, concept = self.init_concepts(Concept("foo").def_var("a", expr), eval_body=True)
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.metadata.pre is None
assert evaluated.metadata.pre is None
assert evaluated.metadata.post is None
assert evaluated.metadata.where is None
assert evaluated.variables() == {"a": Property("a", expected)}
assert evaluated.metadata.is_evaluated
def test_i_can_evaluate_when_the_body_is_the_name_of_the_concept(self):
# to prove that I can distinguish from a string
sheerka, context, concept = self.init_concepts(Concept("foo", body="'foo'"), eval_body=True, create_new=True)
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.body == "foo"
def test_i_can_evaluate_metadata_using_do_not_resolve(self):
sheerka, context, concept = self.init_concepts(Concept("foo"), eval_body=True)
concept.compiled[ConceptParts.BODY] = DoNotResolve("do not resolve")
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.body == "do not resolve"
assert evaluated.metadata.is_evaluated
def test_i_can_evaluate_variable_using_do_not_resolve(self):
sheerka, context, concept = self.init_concepts(Concept("foo").def_var("a"), eval_body=True)
concept.compiled["a"] = DoNotResolve("do not resolve")
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.get_value("a") == "do not resolve"
assert evaluated.metadata.is_evaluated
def test_original_value_is_overridden_when_using_do_no_resolve(self):
concept = Concept("foo", body="original value").def_var("a", "original value")
sheerka, context, concept = self.init_concepts(concept, eval_body=True)
concept.compiled["a"] = DoNotResolve("do not resolve")
concept.compiled[ConceptParts.BODY] = DoNotResolve("do not resolve")
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.body == "do not resolve"
assert evaluated.get_value("a") == "do not resolve"
assert evaluated.metadata.is_evaluated
def test_variables_are_evaluated_before_body(self):
sheerka, context, concept = self.init_concepts(Concept("foo", body="a+1").def_var("a", "10"), eval_body=True)
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated == CB(concept, 11)
def test_i_can_evaluate_when_another_concept_is_referenced(self):
sheerka, context, concept_a, concept = self.init_concepts(
Concept("a"),
Concept("foo", body="a"),
eval_body=True)
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated == CB("foo", CB("a", BuiltinConcepts.NOT_INITIALIZED))
assert evaluated.metadata.is_evaluated
assert evaluated.body.metadata.is_evaluated
def test_i_can_evaluate_when_the_referenced_concept_has_a_body(self):
sheerka, context, concept_a, concept = self.init_concepts(
Concept("a", body="1"),
Concept("foo", body="a"),
eval_body=True)
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.body == CB("a", 1)
assert not concept_a.metadata.is_evaluated
assert evaluated.metadata.is_evaluated
def test_i_can_evaluate_concept_of_concept_when_the_leaf_has_a_body(self):
sheerka, context, concept_a, concept_b, concept_c, concept_d = self.init_concepts(
Concept("a", body="'a'"),
Concept("b", body="a"),
Concept("c", body="b"),
Concept("d", body="c"),
eval_body=True)
evaluated = sheerka.evaluate_concept(context, concept_d)
assert evaluated.key == concept_d.key
expected = CB("c", CB("b", CB("a", "a")))
assert evaluated.body == expected
assert sheerka.objvalue(evaluated) == 'a'
assert evaluated.metadata.is_evaluated
def test_i_can_evaluate_concept_of_concept_does_not_have_a_body(self):
sheerka, context, concept_a, concept_b, concept_c, concept_d = self.init_concepts(
Concept("a"),
Concept("b", body="a"),
Concept("c", body="b"),
Concept("d", body="c"),
eval_body=True)
evaluated = sheerka.evaluate_concept(context, concept_d)
assert evaluated.key == concept_d.key
expected = CB("c", CB("b", CB("a", BuiltinConcepts.NOT_INITIALIZED)))
assert evaluated.body == expected
assert sheerka.objvalue(evaluated) == CB("a", BuiltinConcepts.NOT_INITIALIZED)
assert evaluated.metadata.is_evaluated
def test_i_can_evaluate_concept_when_variables_reference_others_concepts_1(self):
"""
The body references a variable.
The variable reference a concept
The variable name is also the name of a concept
:return:
"""
sheerka, context, concept_a, concept = self.init_concepts(
Concept("a"),
Concept("foo", body="a").def_var("a", "a"),
eval_body=True)
evaluated = sheerka.evaluate_concept(context, concept)
# first, prop a is evaluated to concept_a
# then body is evaluated to prop a -> concept_a
assert evaluated.key == concept.key
assert evaluated.body == concept_a
def test_i_can_evaluate_concept_when_variables_reference_others_concepts_2(self):
"""
Same test,
but the name of the property and the name of the concept are different
:return:
"""
sheerka, context, concept_a = self.init_concepts(Concept(name="a"), eval_body=True)
concept = Concept("foo", body="concept_a").def_var("concept_a", "a")
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.body == concept_a
def test_i_can_evaluate_concept_when_variables_reference_others_concepts_3(self):
"""
The body references a variable.
The variable reference a concept
The name of the variable is also the name of a concept, but the variable points to something else
:return:
"""
sheerka, context, concept_a, concept_b = self.init_concepts("a", "b", eval_body=True)
concept = Concept("foo", body="a").def_var("a", "b")
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.body == concept_b
def test_i_can_evaluate_concept_when_variables_reference_others_concepts_4(self):
"""
The body references a variable.
The variable reference a concept
:return:
"""
sheerka, context, concept_b = self.init_concepts("b", eval_body=True)
concept = Concept("foo", body="a").def_var("a", "b")
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.body == concept_b
def test_i_can_evaluate_concept_when_variables_reference_others_concepts_with_body(self):
sheerka, context, *concepts = self.init_concepts(
Concept(name="a", body="1"),
Concept(name="b", body="2"),
eval_body=True
)
concept = Concept("foo", body="propA + propB").def_var("propA", "a").def_var("propB", "b")
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.body == 3
def test_i_can_evaluate_concept_when_variables_is_a_concept(self):
sheerka, context, concept_a = self.init_concepts(Concept(name="a", body="'a'"), eval_body=True)
concept = Concept("foo").def_var("a")
concept.compiled["a"] = concept_a
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.get_value("a") == CB("a", "a")
def test_i_can_evaluate_concept_when_variable_is_a_concept_token(self):
sheerka, context, concept_a, concept_b = self.init_concepts(
"a",
Concept("b").def_var("var_name", "c:a:"), # c:a: means concept 'a'
eval_body=True)
evaluated = sheerka.evaluate_concept(context, concept_b)
assert evaluated.key == concept_b.key
assert evaluated.get_value("var_name") == concept_a
def test_i_can_evaluate_concept_when_body_isa_concept_token(self):
sheerka, context, concept_a, concept_b = self.init_concepts(
"a",
Concept("b", body="c:a:"), # c:a: means concept 'a'
eval_body=True)
evaluated = sheerka.evaluate_concept(context, concept_b)
assert evaluated.key == concept_b.key
assert evaluated.body == concept_a
def test_i_can_evaluate_when_variable_asts_is_a_list(self):
sheerka = self.get_sheerka()
foo = Concept("foo", body="1")
concept = Concept("to_eval").def_var("prop")
concept.compiled["prop"] = [foo, DoNotResolve("1")]
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept)
variables = evaluated.get_value("prop")
assert len(variables) == 2
assert variables[0] == CB("foo", 1)
assert variables[1] == "1"
def test_i_can_evaluate_when_compiled_is_set_up_with_return_value(self):
sheerka = self.get_sheerka()
python_node = PythonNode("1 +1 ")
parser_result = ParserResultConcept(parser="who", value=python_node)
concept = Concept("to_eval").def_var("prop")
concept.compiled["prop"] = [ReturnValueConcept("who", True, parser_result)]
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept)
assert evaluated.get_value("prop") == 2
# also works when only one return value
concept = Concept("to_eval").def_var("prop")
concept.compiled["prop"] = ReturnValueConcept("who", True, parser_result)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept)
assert evaluated.get_value("prop") == 2
def test_i_can_evaluate_when_body_is_a_concept_with_its_own_variables(self):
sheerka, context, plus, add = self.init_concepts(
Concept("a plus b", body="a + b").def_var("a").def_var("b"),
Concept("add a b", body="a plus b").def_var("a").def_var("b"),
eval_body=True)
add_instance = self.get_concept_instance(sheerka, add, a="1", b="2")
evaluated = sheerka.evaluate_concept(context, add_instance)
assert evaluated.key == add_instance.key
assert evaluated.metadata.is_evaluated
assert sheerka.objvalue(evaluated) == 3
def test_i_can_evaluate_when_body_is_a_concept_with_its_own_variables_and_different_names(self):
sheerka, context, plus, add = self.init_concepts(
Concept("a plus b", body="a + b").def_var("a").def_var("b"),
Concept("add x y", body="x plus y").def_var("x").def_var("y"),
eval_body=True)
add_instance = self.get_concept_instance(sheerka, add, x="1", y="2")
evaluated = sheerka.evaluate_concept(context, add_instance)
assert evaluated.key == add_instance.key
assert evaluated.metadata.is_evaluated
assert sheerka.objvalue(evaluated) == 3
def test_i_can_evaluate_when_body_is_a_concept_with_its_own_variables_multiple_levels(self):
sheerka, context, plus, add, inc = self.init_concepts(
Concept("a plus b", body="a + b").def_var("a").def_var("b"),
Concept("add x y", body="x plus y").def_var("x").def_var("y"),
Concept("inc number", body="add number 1").def_var("number"),
eval_body=True)
inc_instance = self.get_concept_instance(sheerka, inc, number="1")
evaluated = sheerka.evaluate_concept(context, inc_instance)
assert evaluated.key == inc_instance.key
assert evaluated.metadata.is_evaluated
assert sheerka.objvalue(evaluated) == 2
def test_i_can_reference_sheerka(self):
sheerka = self.get_sheerka()
concept = Concept("foo", body="sheerka.test()").init_key()
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept)
assert evaluated.key == concept.key
assert evaluated.body == sheerka.test()
def test_variables_values_takes_precedence_over_the_outside_world(self):
sheerka, context, concept_a, concept_b = self.init_concepts(
Concept(name="a", body="'concept_a'"),
Concept(name="b", body="'concept_b'"),
eval_body=True
)
concept = Concept("foo", body="a")
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.body == CB("a", "concept_a") # this test was already done
# so check this one.
concept = Concept("foo", body="a").def_var("a", "'property_a'")
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.body == 'property_a'
# or this one.
concept = Concept("foo", body="a").def_var("a", "b")
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.body == CB("b", "concept_b")
def test_variables_values_takes_precedence(self):
sheerka, context, concept_a, concept_b = self.init_concepts(
Concept(name="a", body="'concept_a'"),
Concept(name="b", body="'concept_b'"),
eval_body=True
)
concept = Concept("foo", body="a + b").def_var("a", "'prop_a'").init_key()
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.body == 'prop_aconcept_b'
def test_i_can_reference_sub_property_of_a_variable(self):
sheerka, context, concept_a = self.init_concepts(
Concept(name="concept_a").def_var("subProp", "'sub_a'"),
eval_body=True
)
concept = Concept("foo", body="a.subProp").def_var("a", "concept_a")
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated == CB(concept.key, "sub_a")
def test_i_cannot_evaluate_concept_if_variable_is_in_error(self):
sheerka = self.get_sheerka()
concept = Concept(name="concept_a").def_var("subProp", "undef_concept")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)
def test_key_is_initialized_by_evaluation(self):
sheerka = self.get_sheerka()
concept = Concept("foo")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept)
assert evaluated.key == concept.init_key().key
@pytest.mark.parametrize("where_clause, expected, expected_prop, expected_body", [
("True", True, None, BuiltinConcepts.NOT_INITIALIZED),
("False", False, ConceptParts.WHERE, BuiltinConcepts.NOT_INITIALIZED),
("self < 10", False, ConceptParts.WHERE, 10),
("self < 11", True, None, 10),
("a < 20", False, "a", BuiltinConcepts.NOT_INITIALIZED),
("a > 19", True, None, BuiltinConcepts.NOT_INITIALIZED),
("a + self > 20", True, None, 10),
("a + self < 20", False, ConceptParts.WHERE, 10),
])
def test_i_can_evaluate_simple_where(self, where_clause, expected, expected_prop, expected_body):
# We check that the WHERE condition is correctly evaluated
# We also check that the body is evaluated only when it's mandatory
sheerka, context, concept = self.init_concepts(
Concept("foo", body="10", where=where_clause).def_var("a", "20"),
eval_body=False, # to check when the evaluation is forced
eval_where=True,
)
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, True), concept, eval_body=False)
if expected:
assert evaluated.key == concept.key
assert concept.body == expected_body
else:
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONDITION_FAILED)
assert evaluated.body == where_clause
assert evaluated.concept == concept
assert evaluated.prop == expected_prop
assert concept.body == expected_body
def test_i_can_evaluate_where_when_using_other_concept(self):
sheerka, context, foo_true, foo_false = self.init_concepts(
Concept("foo_true", body="True"),
Concept("foo_false", body="False"),
)
concept = Concept("foo", where="foo_true")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, True), concept)
assert evaluated.key == concept.key
concept = Concept("foo", where="foo_false")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, True), concept)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONDITION_FAILED)
assert evaluated.body == "foo_false"
concept = Concept("foo", where="foo_false")
evaluated = sheerka.evaluate_concept(self.get_context(sheerka, False, False), concept)
assert evaluated.key == concept.key
def test_i_can_apply_intermediate_where_condition_using_python(self):
sheerka, context, one_1, one_str, plus = self.init_concepts(
Concept("one", body="1"),
Concept("one", body="'one'"),
Concept("a plus b", body="a + b", where="isinstance(a, int)").def_var("a", "one").def_var("b", "2"),
eval_body=True,
eval_where=True,
)
evaluated = sheerka.evaluate_concept(context, plus)
assert evaluated.key == plus.key
assert evaluated.body == 3
def test_i_can_apply_intermediate_where_condition_when_multiple_variables_using_python(self):
sheerka, context, one_1, one_str, two_2, two_str, plus = self.init_concepts(
Concept("one", body="1"),
Concept("one", body="'one'"),
Concept("two", body="2"),
Concept("two", body="'two'"),
Concept("a plus b",
body="a + b",
where="isinstance(a, int) and isinstance(b, int)").def_var("a", "one").def_var("b", "two"),
eval_body=True,
eval_where=True,
)
evaluated = sheerka.evaluate_concept(context, plus)
assert evaluated.key == plus.key
assert evaluated.body == 3
def test_i_can_apply_intermediate_where_condition_using_other_concepts(self):
sheerka, context, one_1, one_str, is_an_int, plus = self.init_concepts(
Concept("one", body="1"),
Concept("one", body="'one'"),
Concept("x is an int", body="isinstance(x, int)").def_var("x"),
Concept("a plus b", body="a + b", where="a is an int").def_var("a", "one").def_var("b", "2"),
eval_body=True,
eval_where=True,
)
evaluated = sheerka.evaluate_concept(context, plus)
assert evaluated.key == plus.key
assert evaluated.body == 3
def test_i_can_apply_intermediate_where_condition_when_multiple_levels(self):
sheerka, context, one_1, one_str, is_an_int, is_an_integer, plus = self.init_concepts(
Concept("one", body="1"),
Concept("one", body="'one'"),
Concept("x is an int", body="isinstance(x, int)").def_var("x"),
Concept("y is an integer", body="y is an int").def_var("y"),
Concept("a plus b", body="a + b", where="a is an integer").def_var("a", "one").def_var("b", "2"),
eval_body=True,
eval_where=True,
)
evaluated = sheerka.evaluate_concept(context, plus)
assert evaluated.key == plus.key
assert evaluated.body == 3
def test_i_can_apply_intermediate_where_condition_choosing_the_correct_where_concept(self):
# in this test, there are two where conditions with the same name
# We need to use the 'PRE' condition to select the correct one
sheerka, context, one_1, one_str, is_an_int, is_an_integer, plus = self.init_concepts(
Concept("one", body="1"),
Concept("one", body="'one'"),
Concept("x is an int",
body="isinstance(x, int)",
pre="in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)").def_var("x"),
Concept("x is an int", body="False").def_var("x"),
Concept("a plus b", body="a + b", where="a is an int").def_var("a", "one").def_var("b", "2"),
eval_body=True,
eval_where=True,
)
evaluated = sheerka.evaluate_concept(context, plus)
assert evaluated.key == plus.key
assert evaluated.body == 3
@pytest.mark.skip("Not ready for that")
def test_i_can_apply_intermediate_where_condition_when_multiple_variables(self):
sheerka, context, one_1, one_str, two_2, two_str, is_an_int, plus = self.init_concepts(
Concept("one", body="1"),
Concept("one", body="'one'"),
Concept("two", body="2"),
Concept("two", body="'two'"),
Concept("x is an int", body="isinstance(x, int)").def_var("x"),
Concept("a plus b",
body="a + b",
where="a is an int and isinstance(b, int)").def_var("a", "one").def_var("b", "two"),
eval_body=True,
eval_where=True,
)
evaluated = sheerka.evaluate_concept(context, plus)
assert evaluated.key == plus.key
assert evaluated.body == 3
def test_i_cannot_evaluate_when_intermediate_where_condition_fails(self):
sheerka, context, one_1, is_an_int, plus = self.init_concepts(
Concept("one", body="'one'"),
Concept("x is an int", body="isinstance(x, int)").def_var("x"),
Concept("a plus b", body="a + b", where="a is an int").def_var("a", "one").def_var("b", "2"),
eval_body=True,
eval_where=True,
)
evaluated = sheerka.evaluate_concept(context, plus)
assert evaluated.key == BuiltinConcepts.CONDITION_FAILED
assert evaluated.body == "a is an int"
def test_i_can_enable_disable_where_clause_evaluation(self):
sheerka, context, concept = self.init_concepts(
Concept("foo", body="10", where="a > 10").def_var("a", None),
)
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
context.protected_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED)
evaluated = sheerka.evaluate_concept(context, concept)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)
def test_i_can_detect_and_resolve_infinite_recursion_with_numeric_constant(self):
sheerka, context, one_str, one_digit = self.init_concepts(
Concept("one", body="1"),
Concept("1", body="one"),
eval_body=True
)
sheerka.add_in_cache(one_str)
sheerka.add_in_cache(one_digit)
evaluated = sheerka.evaluate_concept(context, one_digit)
assert evaluated.key == one_digit.key
assert evaluated.body == InfiniteRecursionResolved(1)
evaluated = sheerka.evaluate_concept(context, one_str)
assert evaluated.key == one_str.key
assert evaluated.body == InfiniteRecursionResolved(1)
def test_i_can_detect_and_resolve_infinite_recursion_with_boolean_constant(self):
sheerka, context, true_str, true_bool = self.init_concepts(
Concept("true", body="True"),
Concept("True", body="true"),
eval_body=True
)
evaluated = sheerka.evaluate_concept(context, true_str)
assert evaluated.key == true_str.key
assert evaluated.body == InfiniteRecursionResolved(True)
evaluated = sheerka.evaluate_concept(context, 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, context, c1, c2, c3, c4 = self.init_concepts(
Concept("one", body="1"),
Concept("1", body="2"),
Concept("2", body="3"),
Concept("3", body="one"),
eval_body=True
)
for concept in (c1, c2, c3, c4):
evaluated = sheerka.evaluate_concept(context, concept)
assert evaluated.key == concept.key
assert evaluated.body == InfiniteRecursionResolved(3)
def test_i_can_detect_infinite_recursion_when_no_constant(self):
sheerka, context, foo, bar, baz, qux = self.init_concepts(
Concept("foo", body="bar"),
Concept("bar", body="baz"),
Concept("baz", body="qux"),
Concept("qux", body="foo"),
eval_body=True
)
evaluated = sheerka.evaluate_concept(context, foo)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
assert evaluated.body == {foo, bar, baz, qux}
evaluated = sheerka.evaluate_concept(context, bar)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
assert evaluated.body == {foo, bar, baz, qux}
evaluated = sheerka.evaluate_concept(context, baz)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
assert evaluated.body == {foo, bar, baz, qux}
evaluated = sheerka.evaluate_concept(context, 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, context, foo = self.init_concepts(
Concept("foo", body="foo"),
eval_body=True
)
evaluated = sheerka.evaluate_concept(context, foo)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
assert evaluated.body == {foo}
# def test_i_can_detect_auto_recursion_when_evaluating_another_concept(self):
# sheerka, context, one_1, one_str, plus = self.init_concepts(
# Concept("one", body="1"),
# Concept("one", body="one"),
# Concept("a plus b", body="a + b", where="isinstance(a, int)").def_var("a", "one").def_var("b", "2")
# )
#
# evaluated = sheerka.evaluate_concept(context, plus, eval_body=True)
# sheerka.isinstance(evaluated, BuiltinConcepts.CHICKEN_AND_EGG)
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, True), one)
assert evaluated.key == one.key
assert evaluated.body == 1
def test_i_can_evaluate_thousand_concept(self):
sheerka, context, thousand, number, forties, forty, one = self.init_concepts(
Concept("thousand", body="number * 1000").def_var("number"),
Concept("number"),
Concept("forties", body="forty + number").def_var("forty").def_var("number"),
Concept("forty", body="40"),
Concept("one", body="1"),
eval_body=True
)
one = sheerka.new("one")
number2 = sheerka.new("number")
number2.compiled["one"] = one
number2.compiled[ConceptParts.BODY] = one
forties = sheerka.new("forties")
forties.compiled["forty"] = sheerka.new("forty")
forties.compiled["number"] = number2
number1 = sheerka.new("number")
number1.compiled["forties"] = forties
number1.compiled[ConceptParts.BODY] = forties
forty_one_thousand = sheerka.new("thousand")
forty_one_thousand.compiled["number"] = number1
evaluated = sheerka.evaluate_concept(context, forty_one_thousand)
assert evaluated.body == 41000
def test_i_can_evaluate_command(self):
sheerka, context, command = self.init_concepts(Concept("command", body="a = 10"))
evaluated = sheerka.evaluate_concept(context, command)
assert evaluated.key == command.key
assert "a" not in sheerka.locals
sheerka.set_isa(context, command, sheerka.new(BuiltinConcepts.AUTO_EVAL))
evaluated = sheerka.evaluate_concept(context, sheerka.new("command"))
assert evaluated.key == command.key
assert "a" in sheerka.locals
@pytest.mark.parametrize("metadata", [
"where",
"pre",
"post",
"ret"
])
def test_i_cannot_evaluate_python_statement_in_where_pre_post_ret(self, metadata, capsys):
sheerka, context, foo = self.init_concepts("foo")
setattr(foo.metadata, metadata, "a=10; print('10')")
foo.metadata.need_validation = True
evaluated = sheerka.evaluate_concept(context, foo, eval_body=True)
captured = capsys.readouterr()
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)
error = evaluated.body
assert sheerka.isinstance(error, BuiltinConcepts.PYTHON_SECURITY_ERROR)
assert error.prop.value == metadata
assert error.body == "a=10; print('10')"
assert captured.out == ""
def test_python_builtin_function_are_forbidden_in_where_pre_post_ret(self, capsys):
# I do the test only for PRE, as it will be the same for the other ConceptPart
sheerka, context, foo, bar = self.init_concepts(
Concept("foo", body="print('10')"), # print will be executed
Concept("bar", pre="print('10')"), # print won't be executed
)
evaluated = sheerka.evaluate_concept(context, foo, eval_body=True)
captured = capsys.readouterr()
assert evaluated.key == foo.key
assert captured.out == "10\n"
evaluated = sheerka.evaluate_concept(context, bar)
captured = capsys.readouterr()
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONCEPT_EVAL_ERROR)
error = evaluated.body
assert sheerka.isinstance(error, BuiltinConcepts.ERROR)
assert captured.out == ""
def test_i_can_failed_a_concept_when_pre_clause_is_not_validated(self, capsys):
sheerka, context, concept = self.init_concepts(
Concept("foo", pre="in_context('foo')", body="print('10')"),
)
evaluated = sheerka.evaluate_concept(context, concept, eval_body=True)
assert sheerka.isinstance(evaluated, BuiltinConcepts.CONDITION_FAILED)
assert evaluated.body == "in_context('foo')"
assert evaluated.concept == concept
assert evaluated.prop == ConceptParts.PRE
captured = capsys.readouterr()
assert captured.out == ""
@pytest.mark.parametrize("concept, eval_body, expected", [
(Concept("foo"), False, []),
(Concept("foo", pre="pre", post="post", ret="ret", where="where"), False, ["pre", "post"]),
(Concept("foo", pre="pr", post="p", ret="r", where="w"), True, ["pre", "ret", "post", "variables", "body"]),
(Concept("foo", pre="a").def_var("a"), False, ["variables", "pre"]),
(Concept("foo", pre="self"), False, ["body", "pre"]),
(Concept("foo", pre="self + a").def_var("a"), False, ["variables", "body", "pre"]),
(Concept("foo", pre="self + a", ret="ret").def_var("a"), False, ["variables", "body", "pre"]),
(Concept("foo", pre="self + a", ret="ret").def_var("a"), True, ["variables", "body", "pre", "ret"]),
(Concept("foo", body="body"), False, [])
])
def test_i_can_compute_metadata_to_eval(self, concept, eval_body, expected):
sheerka, context, concept = self.init_concepts(concept)
service = sheerka.services[SheerkaEvaluateConcept.NAME]
if eval_body:
context.add_to_protected_hints(BuiltinConcepts.EVAL_BODY_REQUESTED)
service.initialize_concept_asts(context, concept)
assert service.compute_metadata_to_eval(context, concept) == expected
def test_i_can_compute_metadata_to_eval_for_where_and_body(self):
sheerka = self.get_sheerka()
service = sheerka.services[SheerkaEvaluateConcept.NAME]
context = self.get_context(sheerka, eval_where=True)
concept = Concept("foo", where="where")
service.initialize_concept_asts(context, concept)
assert service.compute_metadata_to_eval(context, concept) == ["where"]
concept = Concept("foo", where="where a").def_var("a")
service.initialize_concept_asts(context, concept)
assert service.compute_metadata_to_eval(context, concept) == ["variables", "where"]
concept = Concept("foo", where="where self")
service.initialize_concept_asts(context, concept)
assert service.compute_metadata_to_eval(context, concept) == ["body", "where"]
context = self.get_context(sheerka, eval_body=True)
concept = Concept("foo")
assert service.compute_metadata_to_eval(context, concept) == ["variables", "body"]
context = self.get_context(sheerka, eval_body=True)
concept = Concept("foo").def_var("a")
assert service.compute_metadata_to_eval(context, concept) == ["variables", "body"]
context = self.get_context(sheerka, eval_body=True)
concept = Concept("foo", body="body").def_var("a")
assert service.compute_metadata_to_eval(context, concept) == ["variables", "body"]
@pytest.mark.parametrize("concept, expected", [
(Concept("foo"), True),
])
def test_is_evaluated_is_correctly_set(self, concept, expected):
sheerka, context, concept = self.init_concepts(concept)
evaluated = sheerka.evaluate_concept(context, concept, eval_body=True)
assert evaluated.key == concept.key
assert concept.metadata.is_evaluated == expected
def test_i_only_compute_the_requested_metadata(self):
sheerka, context, concept = self.init_concepts(
Concept("foo", pre="'pre'", post="'post'", ret="'ret'", where="'where'", body="'body'").def_var("a", "'a'")
)
context.protected_hints.add(BuiltinConcepts.EVAL_WHERE_REQUESTED) # to prove that we do not care
context.protected_hints.add(BuiltinConcepts.EVAL_BODY_REQUESTED) # to prove that we do not care
evaluated = sheerka.evaluate_concept(context, concept, metadata=['pre'])
assert evaluated.values == {"a": Property("a", NotInit), ConceptParts.PRE: Property(ConceptParts.PRE, 'pre')}
def test_i_can_manage_ret(self):
sheerka, context, foo, bar = self.init_concepts("foo", Concept("bar", ret="foo"))
res = sheerka.evaluate_concept(context, bar)
assert res.id == bar.id
res = sheerka.evaluate_concept(context, bar, eval_body=True)
assert res.id == foo.id
def test_ret_is_evaluated_only_is_body_is_requested(self):
sheerka, context, foo, bar = self.init_concepts("foo", Concept("bar", ret="__NOT_FOUND"))
res = sheerka.evaluate_concept(context, bar, eval_body=False)
assert res.id == bar.id
# I cannot implement value cache for now
# def test_values_when_no_variables_are_computed_only_once(self):
# sheerka, context, foo = self.init_concepts(Concept("foo", body="10"))
#
# evaluated = sheerka.evaluate_concept(context, sheerka.new("foo"), eval_body=True)
# assert evaluated.body == 10
# assert len(evaluated.compiled) > 0
#
# evaluated_2 = sheerka.evaluate_concept(context, sheerka.new("foo"), eval_body=True)
# assert evaluated_2.body == 10
# assert len(evaluated_2.compiled) == 0