e69745adc8
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
337 lines
15 KiB
Python
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
|