Files
Sheerka-Old/tests/core/test_builtin_helpers.py
T
kodjo e69745adc8 Fixed #100 : SheerkaAdmin: Add builtins() command
Fixed #99 : SheerkaQueryManager: I can manage contains predicate when filtering objects
Fixed #97 : ERROR: list indices must be integers or slices, not Concept
Fixed #96 : SequenceNodeParser: SequenceNodeParser must correctly handle concept definition
Fixed #95 : ResolveAmbiguity must not remove concepts that do not require evaluation
Fixed #94 : Concepts with the same key are lost when new ontology
Fixed #93 : Introduce BuiltinConcepts.EVAL_GLOBAL_TRUTH_REQUESTED
Fixed #92 : ExpressionParser: Implement compile_disjunctions()
Fixed #91 : Implement get_concepts_complexity(context, concepts, concept_parts)
Fixed #90 : ResolveAmbiguity : where predicate is not used to resolve ambiguity
Fixed #89 : ResolveAmbiguityEvaluator: Concepts embedded in ConceptNode are not resolved
Fixed #88: SyaNodeParser: Parse multiple parameters when some of the are not recognized
Fixed #87: SyaNodeParser : Parse the multiple parameters
2021-07-31 08:52:00 +02:00

337 lines
15 KiB
Python

import pytest
import core.builtin_helpers
from core.builtin_concepts import ReturnValueConcept, BuiltinConcepts
from core.concept import Concept
from core.global_symbols import NotInit
from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import Tokenizer
from evaluators.BaseEvaluator import BaseEvaluator
from evaluators.ValidateConceptEvaluator import ValidateConceptEvaluator
from parsers.BaseNodeParser import ConceptNode
from parsers.BaseParser import BaseParser
from parsers.SyaNodeParser import SyaNodeParser
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
class TestBuiltinHelpers(TestUsingMemoryBasedSheerka):
def test_i_can_use_expect_one_when_empty(self):
sheerka = self.get_sheerka()
res = core.builtin_helpers.expect_one(self.get_context(sheerka), [])
assert not res.status
assert sheerka.isinstance(res.value, BuiltinConcepts.IS_EMPTY)
def test_i_can_use_expect_one_when_too_many_success(self):
sheerka = self.get_sheerka()
items = [
ReturnValueConcept("who", True, "value1"),
ReturnValueConcept("who", True, "value2"),
]
res = core.builtin_helpers.expect_one(self.get_context(sheerka), items)
assert not res.status
assert sheerka.isinstance(res.value, BuiltinConcepts.TOO_MANY_SUCCESS)
assert res.value.body == items
assert res.parents == items
def test_i_can_use_expect_one_when_same_success(self):
sheerka = self.get_sheerka()
items = [
ReturnValueConcept("who", True, "value"),
ReturnValueConcept("who", True, "value"),
]
res = core.builtin_helpers.expect_one(self.get_context(sheerka), items)
assert res.status
assert res.value == items[0].value
assert res.parents == items
def test_i_can_use_expect_when_only_errors_1(self):
sheerka = self.get_sheerka()
items = [
ReturnValueConcept("who", False, sheerka.new(BuiltinConcepts.ERROR)),
]
res = core.builtin_helpers.expect_one(self.get_context(sheerka), items)
assert not res.status
assert res.value == items[0].body
def test_i_can_use_expect_when_only_errors_2(self):
sheerka = self.get_sheerka()
items = [
ReturnValueConcept("who", False, None),
ReturnValueConcept("who", False, None),
]
res = core.builtin_helpers.expect_one(self.get_context(sheerka), items)
assert not res.status
assert sheerka.isinstance(res.value, BuiltinConcepts.TOO_MANY_ERRORS)
assert res.value.body == items
assert res.parents == items
def test_i_can_use_expect_one_when_one_success_1(self):
sheerka = self.get_sheerka()
items = [
ReturnValueConcept("who", True, None),
]
res = core.builtin_helpers.expect_one(self.get_context(sheerka), items)
assert res.status
assert res.body == items[0].body
def test_i_can_use_expect_one_when_one_success_2(self):
sheerka = self.get_sheerka()
items = [
ReturnValueConcept("who", False, None),
ReturnValueConcept("who", True, None),
ReturnValueConcept("who", False, None),
]
res = core.builtin_helpers.expect_one(self.get_context(sheerka), items)
assert res.status
assert res.body == items[1].body
assert res.parents == items
def test_i_can_use_expect_one_when_not_a_list_true(self):
sheerka = self.get_sheerka()
item = ReturnValueConcept("who", True, None)
res = core.builtin_helpers.expect_one(self.get_context(sheerka), item)
assert res.status
assert res == item
def test_i_can_use_expect_one_when_not_a_list_false(self):
sheerka = self.get_sheerka()
item = ReturnValueConcept("who", False, None)
res = core.builtin_helpers.expect_one(self.get_context(sheerka), item)
assert not res.status
assert res == item
# @pytest.mark.parametrize("expression, vars_to_include, vars_to_exclude, expected_expr", [
# ("a == 1", [], [], []),
# ("a == 1", ["a"], [], ["a == 1"]),
# ("a == 1", [], ["a"], []),
# ("predicate(a)", [], [], []),
# ("predicate(a)", ["a"], [], ["predicate(a)"]),
# ("predicate(a, b)", ["a"], [], ["predicate(a, b)"]),
# ("predicate(a, b)", ["b"], [], ["predicate(a, b)"]),
# ("predicate(a, b)", ["a", "b"], [], ["predicate(a, b)"]),
# ("predicate(a, b)", ["a"], ["b"], []),
# ("a + b == 1", [], [], []),
# ("a + b == 1", ["a"], [], ["a + b == 1"]),
# ("a + b == 1", ["a"], ["b"], []),
# ("a + b == 1", ["b"], [], ["a + b == 1"]),
# ("a + b == 1", ["a", "b"], [], ["a + b == 1"]),
# ("a == 1 and b == 2", [], [], []),
# ("a == 1 and b == 2", ["a"], [], ["a == 1"]),
# ("a == 1 and b == 2", ["b"], [], ["b == 2"]),
# ("a == 1 and b == 2", ["a"], ["b"], ["a == 1"]),
# ("a == 1 and b == 2", ["a", "b"], [], ["a == 1 and b == 2"]),
# ("predicate(a,c) and predicate(b,c)", ["a", "b"], [], ["predicate(a,c) and predicate(b,c)"]),
# ("not(a == 1)", [], [], []),
# ("not(a == 1)", ["a"], [], ["not(a==1)"]),
# ("a == 1 or b == 2", [], [], []),
# ("a == 1 or b == 2", ["a"], [], ["a == 1"]),
# ("a == 1 or b == 2", ["b"], [], ["b == 2"]),
# ("a == 1 or b == 2", ["a", "b"], [], ["a == 1 or b == 2"]),
# ("predicate(a,c) or predicate(b,c)", ["a", "b"], [], ["predicate(a,c) or predicate(b,c)"]),
# ("a < 1 and a > b", ["a"], [], ["a < 1 and a > b"]),
# ])
# def test_i_can_extract_predicates(self, expression, vars_to_include, vars_to_exclude, expected_expr):
# sheerka = self.get_sheerka()
# expected = [ast.parse(expr, mode="eval") for expr in expected_expr]
#
# actual = core.builtin_helpers.extract_predicates(sheerka, expression, vars_to_include, vars_to_exclude)
# assert len(actual) == len(expected)
# for i in range(len(actual)):
# assert self.dump_ast(actual[i]) == self.dump_ast(expected[i])
@pytest.mark.parametrize("concepts, expected", [
([], []),
([Concept("foo", pre="False"), Concept("bar")], ["bar"]),
([Concept("foo", pre="True"), Concept("bar")], ["foo"]),
([Concept("foo").def_var("a"), Concept("bar")], ["bar"]), # less variables is better
([Concept("foo"), Concept("bar")], ["foo", "bar"]),
([Concept("foo", pre="is_question()"), Concept("bar")], ["bar"]),
])
def test_i_can_resolve_ambiguity_when_empty(self, concepts, expected):
context = self.get_context()
res = core.builtin_helpers.resolve_ambiguity(context, concepts)
assert [c.name for c in res] == expected
@pytest.mark.parametrize("pre, expected", [
("x and y", False),
("is_question()", True),
(" is_question ( ) ", True),
("context.in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)", True),
(" context . in_context ( BuiltinConcepts . EVAL_QUESTION_REQUESTED ) ", True),
("in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)", True),
(None, False),
("", False),
(NotInit, False),
("is _ question()", False),
("is_ question()", False),
("is _question()", False),
("context.in _context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)", False),
("not is_question()", False),
("not context.in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)", False),
("is_question() and True", True),
("is_question() and False", True), # don't care about the second argument if it is not related to question
("is_question() and xxx", True), # don't care about the second argument if it is not related to question
("is_question() and not is_question()", False), # error ?
("is_question() and not context.in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)", False), # error ?
])
def test_is_a_question(self, pre, expected):
sheerka, context = self.init_test().unpack()
concept = Concept("foo", pre=pre)
assert core.builtin_helpers.is_a_question(context, concept) == expected
def test_context_hints_are_reset_when_call_evaluate_from_source(self):
sheerka, context, one = self.init_concepts(Concept("one", body="1"))
context.add_to_global_hints(BuiltinConcepts.EVAL_BODY_REQUESTED)
context.add_to_protected_hints(BuiltinConcepts.EVAL_BODY_REQUESTED)
context.add_to_private_hints(BuiltinConcepts.EVAL_BODY_REQUESTED)
res = core.builtin_helpers.evaluate_from_source(context, "one", eval_body=False)
evaluated = [r for r in res if r.status][0].body
assert evaluated.body is NotInit
def test_i_can_evaluate_from_source_with_specific_evaluators(self):
sheerka, context, one = self.init_concepts(Concept("foo", body="'hello world'"))
res = core.builtin_helpers.evaluate_from_source(context, "foo", eval_body=True, evaluators=["Python"])
res = self.successful_return_values(res)
assert len(res) == 1
assert res[0].who.startswith(BaseParser.PREFIX) # Cannot evaluate concept with PythonEvaluator
res = core.builtin_helpers.evaluate_from_source(context, "foo", eval_body=True, evaluators=["Concept"])
res = self.successful_return_values(res)
assert len(res) == 1
assert res[0].who == BaseEvaluator.PREFIX + "Concept"
assert sheerka.isinstance(res[0].body.body,
BuiltinConcepts.PARSER_RESULT) # cannot eval 'hello world' without PythonEvaluator
res = core.builtin_helpers.evaluate_from_source(context, "foo", eval_body=True,
evaluators=["Concept", "Python"])
res = self.successful_return_values(res)
assert len(res) == 1
assert res[0].who == BaseEvaluator.PREFIX + "Concept"
assert res[0].body.body == "hello world"
def test_i_can_get_lexer_nodes_after_parsing_validation(self):
sheerka, context, the, foo = self.init_concepts(
Concept("the x", ret="x", where="isinstance(x, Concept)").def_var("x"),
"foo",
create_new=True)
parsed_ret_val = SyaNodeParser().parse(context, ParserInput("the foo"))
validated_ret_val = ValidateConceptEvaluator().eval(context, parsed_ret_val)
res = core.builtin_helpers.get_lexer_nodes([validated_ret_val], 0, list(Tokenizer("the foo", yield_eof=False)))
assert isinstance(res, list)
assert isinstance(res[0][0], ConceptNode)
def test_ensure_evaluated_returns_the_ret_value(self):
"""
When a concept has a RET defined, make sure to return it
:return:
"""
sheerka, context, foo, bar = self.init_concepts(
"foo",
Concept("bar", ret="foo")
)
assert core.builtin_helpers.ensure_evaluated(context, bar) == foo
# a second time, now that bar is already evaluated
assert core.builtin_helpers.ensure_evaluated(context, bar) == foo
@pytest.mark.parametrize("concept, concepts_parts, expected", [
(Concept("foo"), ["where"], 0),
(Concept("foo", where="x"), ["where"], 1),
(Concept("foo", where="x and y"), ["where"], 2),
(Concept("foo", where="x or y"), ["where"], 1),
(Concept("foo", where="x or y and z"), ["where"], 2),
(Concept("foo", where="not w"), ["where"], 1),
(Concept("foo", where=""), ["where"], 0),
(Concept("foo", pre="x"), ["pre", "where"], 101),
(Concept("foo", where="x"), ["pre", "where"], 1),
(Concept("foo", where="x and y", pre="z"), ["pre", "where"], 103),
(Concept("foo", pre="x"), ["pre|where"], 1),
(Concept("foo", where="x"), ["pre|where"], 1),
(Concept("foo", where="x and y", pre="z"), ["pre|where"], 3),
])
def test_i_can_get_concept_complexity(self, concept, concepts_parts, expected):
context = self.get_context()
assert core.builtin_helpers.get_concept_complexity(context, concept, concepts_parts) == expected
# @pytest.mark.parametrize("return_values", [
# None,
# []
# ])
# def test_i_can_resolve_simple_ambiguity_when_no_return_values(self, return_values):
# context = self.get_context()
#
# assert core.builtin_helpers.remove_ambiguity(context, return_values) == return_values
# def test_resolve_ambiguity_concepts_with_no_variable_take_precedence(self):
# context = self.get_context()
# return_values = [
# self.pretval(Concept("hello a").def_var("a", "world"), "hello word"),
# self.pretval(Concept("hello world"), "hello word"),
# # self.pretval(Concept("hello world", pre="False"), "hello word"),
# self.retval(Concept("not a parser result")),
# self.retval(Concept("status is false"), status=False),
# self.pretval(Concept("false parser result"), status=False),
# ]
#
# ret = core.builtin_helpers.remove_ambiguity(context, return_values)
# assert ret.status
# assert ret.parents == return_values
#
# filtered = ret.body
# assert context.sheerka.isinstance(ret.body, BuiltinConcepts.FILTERED)
# assert filtered.body == [
# return_values[2],
# return_values[3],
# return_values[4],
# return_values[1],
# ]
# assert filtered.iterable == return_values
# assert filtered.predicate == "remove_ambiguity(context, iterable)"
#
# def test_resolve_ambiguity_failed_pre_condition_are_discarded(self):
# context = self.get_context()
# return_values = [
# self.pretval(Concept("hello world"), "hello word"),
# self.pretval(Concept("hello world", pre="False"), "hello word"),
# ]
#
# ret = core.builtin_helpers.remove_ambiguity(context, return_values)
# filtered = ret.body
# assert context.sheerka.isinstance(ret.body, BuiltinConcepts.FILTERED)
# assert filtered.body == [
# return_values[0],
# ]
#
# def test_resolve_ambiguity_original_return_value_is_returned_when_nothing_to_filter(self):
# context = self.get_context()
# return_values = [
# self.pretval(Concept("hello a").def_var("a", "world"), "hello word"),
# self.retval(Concept("not a parser result")),
# self.retval(Concept("status is false"), status=False),
# self.pretval(Concept("false parser result"), status=False),
# ]
#
# assert core.builtin_helpers.remove_ambiguity(context, return_values) == return_values