import pytest from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, ParserResultConcept from core.concept import Concept, DoNotResolve, ConceptParts, InfiniteRecursionResolved, \ concept_part_value, DEFINITION_TYPE_DEF from core.global_symbols import NotInit, NotFound from core.sheerka.services.SheerkaEvaluateConcept import SheerkaEvaluateConcept from core.sheerka.services.SheerkaMemory import SheerkaMemory from parsers.BaseParser import BaseParser from parsers.PythonParser import PythonNode, PythonParser from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka from tests.evaluators.EvaluatorTestsUtils import pr_ret_val, python_ret_val from tests.parsers.parsers_utils import CB, compare_with_test_object class TestSheerkaEvaluateConcept(TestUsingMemoryBasedSheerka): @pytest.mark.parametrize("body, 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_simple_body(self, body, expected): sheerka, context, concept = self.init_test(eval_body=True).with_concepts(Concept("foo", body=body)).unpack() evaluated = sheerka.evaluate_concept(context, concept) assert evaluated.key == concept.key assert evaluated.body == expected assert evaluated.get_metadata().body == body assert evaluated.get_metadata().pre is None assert evaluated.get_metadata().post is None assert evaluated.get_metadata().where is None assert evaluated.variables() == {} assert evaluated.get_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.get_metadata().body is None assert evaluated.get_metadata().post == expr assert evaluated.get_metadata().pre is None assert evaluated.get_metadata().where is None assert evaluated.get_value(ConceptParts.POST) == expected assert evaluated.variables() == {} assert not evaluated.get_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_variable(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.get_metadata().pre is None assert evaluated.get_metadata().pre is None assert evaluated.get_metadata().post is None assert evaluated.get_metadata().where is None assert evaluated.variables() == {"a": expected} assert evaluated.get_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_test(eval_body=True).with_concepts( Concept("foo", body="'foo'"), create_new=True).unpack() 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.get_compiled()[ConceptParts.BODY] = DoNotResolve("do not resolve") evaluated = sheerka.evaluate_concept(context, concept) assert evaluated.body == "do not resolve" assert evaluated.get_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.get_compiled()["a"] = DoNotResolve("do not resolve") evaluated = sheerka.evaluate_concept(context, concept) assert evaluated.get_value("a") == "do not resolve" assert evaluated.get_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.get_compiled()["a"] = DoNotResolve("do not resolve") concept.get_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.get_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) compare_with_test_object(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) compare_with_test_object(evaluated, CB("foo", CB("a", NotInit))) assert evaluated.get_metadata().is_evaluated assert evaluated.body.get_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 compare_with_test_object(evaluated.body, CB("a", 1)) assert not concept_a.get_metadata().is_evaluated assert evaluated.get_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"))) compare_with_test_object(evaluated.body, expected) assert sheerka.objvalue(evaluated) == 'a' assert evaluated.get_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", NotInit))) compare_with_test_object(evaluated.body, expected) compare_with_test_object(sheerka.objvalue(evaluated), CB("a", NotInit)) assert evaluated.get_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.get_compiled()["a"] = concept_a evaluated = sheerka.evaluate_concept(context, concept) assert evaluated.key == concept.key compare_with_test_object(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.get_compiled()["prop"] = [foo, DoNotResolve("1")] evaluated = sheerka.evaluate_concept(self.get_context(sheerka, True), concept) variables = evaluated.get_value("prop") assert len(variables) == 2 compare_with_test_object(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 ").init_ast() parser_result = ParserResultConcept(parser="who", value=python_node) concept = Concept("to_eval").def_var("prop") concept.get_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.get_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.get_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.get_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.get_metadata().is_evaluated assert sheerka.objvalue(evaluated) == 2 def test_i_can_evaluate_a_concept_that_references_another_concept_twice(self): """ Test that a new instance of concept is return when the metadata refers to a concept :return: """ sheerka, context, predicate, foo = self.init_concepts( Concept("Sometimes True", body="in_context('a')"), Concept("foo", pre="c:Sometimes True:")) foo1 = sheerka.new("foo") foo1 = sheerka.evaluate_concept(context, foo1) # 'a' is not in context, so it fails context2 = self.get_context(sheerka) context2.add_to_protected_hints('a') foo2 = sheerka.new("foo") foo2 = sheerka.evaluate_concept(context2, foo2) # 'a' in context + new instance of 'Sometimes True' assert sheerka.isinstance(foo1, BuiltinConcepts.CONDITION_FAILED) assert sheerka.isinstance(foo2, "foo") 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 compare_with_test_object(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 compare_with_test_object(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) compare_with_test_object(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, NotInit), ("False", False, ConceptParts.WHERE, NotInit), ("self < 10", False, ConceptParts.WHERE, 10), ("self < 11", True, None, 10), ("a < 20", False, "a", NotInit), ("a > 19", True, None, NotInit), ("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 == str(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.test_only_add_in_cache(one_str) sheerka.test_only_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_infinite_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.get_compiled()["one"] = one number2.get_compiled()[ConceptParts.BODY] = one forties = sheerka.new("forties") forties.get_compiled()["forty"] = sheerka.new("forty") forties.get_compiled()["number"] = number2 number1 = sheerka.new("number") number1.get_compiled()["forties"] = forties number1.get_compiled()[ConceptParts.BODY] = forties forty_one_thousand = sheerka.new("thousand") forty_one_thousand.get_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 sheerka.get_from_memory(context, "a") == NotFound sheerka.set_isa(context, command, sheerka.new(BuiltinConcepts.AUTO_EVAL)) evaluated = sheerka.evaluate_concept(context, sheerka.new("command")) assert evaluated.key == command.key assert sheerka.get_from_memory(context, "a").obj == 10 @pytest.mark.parametrize("metadata", [ ConceptParts.WHERE, ConceptParts.PRE, ConceptParts.POST, ConceptParts.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.get_metadata(), concept_part_value(metadata), "a=10; print('10')") foo.get_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 == 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="a").def_var("a") service.initialize_concept_asts(context, concept) assert service.compute_metadata_to_eval(context, concept) == ["variables", "#where#"] concept = Concept("foo", 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.get_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=[ConceptParts.PRE]) assert evaluated.values() == {"a": NotInit, 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 def test_i_can_eval_concept_with_rules(self): sheerka, context, foo = self.init_concepts(Concept("foo a", body="a.name").def_var("a", "r:|1:")) res = sheerka.evaluate_concept(context, foo, eval_body=True) assert res.body == "Print return values" def test_i_can_manage_python_concept_infinite_recursion_when_initializing_ast(self): sheerka, context, foo = self.init_concepts(Concept("a + b", body="a + b").def_var("a").def_var("b")) evaluator = SheerkaEvaluateConcept(sheerka) evaluator.initialize_concept_asts(context, foo) res = foo.get_compiled()["#body#"] assert len(res) == 1 assert sheerka.isinstance(res[0], BuiltinConcepts.RETURN_VALUE) assert res[0].who == BaseParser.get_name(PythonParser.NAME) # TODO validate that a rule is created def test_can_detect_recursive_definition_with_exact_concept(self): sheerka, context, foo = self.init_concepts("foo") evaluator = SheerkaEvaluateConcept(sheerka) # 'def concept foo as foo' return_values = [pr_ret_val(foo, parser="ExactConcept"), python_ret_val("foo")] res = evaluator.get_recursive_definitions(foo, return_values) assert list(res) == [BaseParser.get_name("ExactConcept")] def test_i_can_detect_when_no_recursive_definition(self): sheerka, context, foo, bar = self.init_concepts("foo", "bar") evaluator = SheerkaEvaluateConcept(sheerka) # 'def concept foo as bar' return_values = [pr_ret_val(bar, parser="ExactConcept"), python_ret_val("foo")] res = evaluator.get_recursive_definitions(foo, return_values) assert list(res) == [] def test_i_can_detect_when_no_recursive_definition2(self): sheerka, context, q = self.init_concepts( Concept("q", definition="q ?", definition_type=DEFINITION_TYPE_DEF).def_var("q")) evaluator = SheerkaEvaluateConcept(sheerka) # i dunno how to construct the return value return_values = [pr_ret_val(q, parser="ExactConcept")] res = evaluator.get_recursive_definitions(q, return_values) assert list(res) == [] # 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.get_compiled()) > 0 # # evaluated_2 = sheerka.evaluate_concept(context, sheerka.new("foo"), eval_body=True) # assert evaluated_2.body == 10 # assert len(evaluated_2.get_compiled()) == 0