Files
Sheerka-Old/tests/core/test_SheerkaEvaluateRules.py
T
kodjo 1059ce25c5 Fixed #68: Implement SheerkaQL
Fixed #70: SheerkaFilterManager : Pipe functions
Fixed #71: SheerkaFilterManager : filter_objects
Fixed #75: SheerkaMemory: Enhance memory() to use the filtering capabilities
Fixed #76: SheerkaEvaluateConcept: Concepts that modify the state of the system must not be evaluated during question
2021-04-26 19:13:47 +02:00

252 lines
12 KiB
Python

import operator
import pytest
from core.builtin_concepts_ids import BuiltinConcepts
from core.concept import Concept, DEFINITION_TYPE_DEF
from core.rule import Rule, ACTION_TYPE_EXEC
from core.sheerka.Sheerka import RECOGNIZED_BY_ID, RECOGNIZED_BY_NAME
from core.sheerka.services.SheerkaEvaluateRules import SheerkaEvaluateRules, LOW_PRIORITY_RULES, DISABLED_RULES
from core.sheerka.services.SheerkaExecute import ParserInput
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, CompiledCondition
from evaluators.PythonEvaluator import PythonEvaluator
from parsers.PythonParser import PythonParser
from sheerkapython.python_wrapper import Expando
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
class TestSheerkaEvaluateRules(TestUsingMemoryBasedSheerka):
def test_i_can_evaluate_python_rules(self):
sheerka, context, r1, r2, r3, r4, r5, r6, r7, r8, r9 = self.init_test().with_format_rules(
Rule(predicate="a == 1", action="", priority=1), # r1
Rule(predicate="a == 2", action="", priority=1), # r2
Rule(predicate="a == 3", action="", priority=0), # r3
Rule(predicate="a == 4", action="", priority=0), # r4
Rule(predicate="a == 5", action="", priority=0), # r5
Rule(predicate="a == 1", action="", priority=1), # r6
Rule(predicate="a == 7", action="", priority=1, is_enabled=False), # r7
Rule(predicate="a == 8", action="", priority=1), # r8
Rule(predicate="a == 9", action="", priority=2), # r9
).unpack()
service = sheerka.services[SheerkaEvaluateRules.NAME]
rules = sorted([r1, r2, r3, r4, r5, r6, r7, r8, r9], key=operator.attrgetter('priority'), reverse=True)
res = service.evaluate_rules(context, rules, {"a": 1}, set())
assert res == {
True: [r1, r6],
False: [r9, r2, r8],
LOW_PRIORITY_RULES: [r3, r4, r5],
DISABLED_RULES: [r7]
}
@pytest.mark.skip("Not ready for that")
def test_i_can_evaluate_question_concept_rules(self):
sheerka, context, concept, r1, r2, r3, r4, r5, r6, r7, r8, r9 = self.init_test().with_concepts(
Concept("x equals y", body="x == y", pre="is_question()").def_var("x").def_var("y"),
create_new=True).with_format_rules(
Rule(predicate="a equals 1", action="", priority=1), # r1
Rule(predicate="a equals 2", action="", priority=1), # r2
Rule(predicate="a equals 3", action="", priority=0), # r3
Rule(predicate="a equals 4", action="", priority=0), # r4
Rule(predicate="a equals 5", action="", priority=0), # r5
Rule(predicate="a equals 1", action="", priority=1), # r6
Rule(predicate="a equals 7", action="", priority=1, is_enabled=False), # r7
Rule(predicate="a equals 8", action="", priority=1), # r8
Rule(predicate="a equals 9", action="", priority=2), # r9
).unpack()
service = sheerka.services[SheerkaEvaluateRules.NAME]
rules = sorted([r1, r2, r3, r4, r5, r6, r7, r8, r9], key=operator.attrgetter('priority'), reverse=True)
res = service.evaluate_rules(context, rules, {"a": 1}, set())
assert res == {
True: [r1, r6],
False: [r9, r2, r8],
LOW_PRIORITY_RULES: [r3, r4, r5],
DISABLED_RULES: [r7]
}
@pytest.mark.parametrize("predicates", [
("True", "False"),
("False", "True"),
])
def test_i_can_eval_when_multiple_python_predicates(self, predicates):
"""
In this test, the rule has multiple predicates to evaluate
The test make sure that is one predicate is successful, the rule must be evaluated
"""
sheerka, context, my_rule = self.init_test().with_format_rules(Rule("my rule"),
compile_rule=False,
create_new=False).unpack()
service = sheerka.services[SheerkaEvaluateRules.NAME]
# create fake compiled predicates
parser = PythonParser()
my_rule.compiled_conditions = [
CompiledCondition(PythonEvaluator.NAME, parser.parse(context, ParserInput(exp)), set(), set(), None, set())
for exp in predicates]
my_rule.metadata.is_compiled = True
my_rule.metadata.is_enabled = True
res = service.evaluate_rules(context, [my_rule], {}, set())
assert res == {
True: [my_rule],
}
@pytest.mark.skip("Not ready for that")
def test_i_can_evaluate_rules_when_concepts_are_questions(self):
sheerka, context, isa, cat, crocodile, pet, r1, r2, r3 = self.init_test().with_concepts(
Concept("x is a y", body="isa(x,y)", pre="is_question()").def_var("x").def_var("y"),
"cat",
"crocodile",
"pet",
create_new=True).with_format_rules(
Rule(predicate="cat is a pet", action=""),
Rule(predicate="crocodile is a pet", action=""),
Rule(predicate="not crocodile is a pet", action=""),
).unpack()
sheerka.set_isa(context, cat, pet)
service = sheerka.services[SheerkaEvaluateRules.NAME]
res = service.evaluate_rules(context, [r1, r2, r3], {}, set())
assert res == {True: [r1, r3], False: [r2]}
@pytest.mark.parametrize("predicate", [
"recognize(__ret.body, greetings)",
"recognize(__ret.body, c:|1001:)",
"recognize(__ret.body, hello 'kodjo')"
])
def test_i_can_evaluate_rules_when_concepts_are_not_questions(self, predicate):
"""
In this test, we evaluate rules that involves concepts that are not questions
"""
sheerka, context, greetings, rule = self.init_test().with_concepts(
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
create_new=True).with_format_rules(
Rule(predicate=predicate, action="")).unpack()
service = sheerka.services[SheerkaEvaluateRules.NAME]
ret = sheerka.ret("evaluator", True, sheerka.new(greetings, a="kodjo"))
res = service.evaluate_rules(context, [rule], {"__ret": ret}, set())
assert res == {True: [rule]}
@pytest.mark.parametrize("recognized_by", [
RECOGNIZED_BY_ID,
RECOGNIZED_BY_NAME,
None
])
def test_i_can_evaluate_concept_rules_when_variable_is_a_one_word_concept(self, recognized_by):
"""
In this test, we evaluate rules that involves concepts that are not questions
"""
sheerka, context, greetings, there, rule = self.init_test().with_concepts(
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
Concept("there"),
create_new=True).with_format_rules(
Rule(predicate="recognize(__ret.body, hello there)", action="")).unpack()
service = sheerka.services[SheerkaEvaluateRules.NAME]
there_instance = sheerka.new_from_template(there, there.key)
if recognized_by:
there_instance.set_hint(BuiltinConcepts.RECOGNIZED_BY, recognized_by)
ret = sheerka.ret("evaluator", True, sheerka.new(greetings, a=there_instance))
res = service.evaluate_rules(context, [rule], {"__ret": ret}, set())
assert res == {True: [rule]}
@pytest.mark.parametrize("recognized_by", [
RECOGNIZED_BY_ID,
RECOGNIZED_BY_NAME,
None
])
def test_i_can_evaluate_concept_rules_when_variable_is_a_two_words_concept(self, recognized_by):
"""
In this test, we evaluate rules that involves concepts that are not questions
"""
sheerka, context, greetings, my_friend, rule = self.init_test().with_concepts(
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
Concept("my friend"),
create_new=True).with_format_rules(
Rule(predicate="recognize(__ret.body, hello my friend)", action="")).unpack()
service = sheerka.services[SheerkaEvaluateRules.NAME]
my_friend_instance = sheerka.new_from_template(my_friend, my_friend.key)
if recognized_by:
my_friend_instance.set_hint(BuiltinConcepts.RECOGNIZED_BY, recognized_by)
ret = sheerka.ret("evaluator", True, sheerka.new(greetings, a=my_friend_instance))
res = service.evaluate_rules(context, [rule], {"__ret": ret}, set())
assert res == {True: [rule]}
def test_i_can_evaluate_concept_rules_when_variable_is_an_expando(self):
sheerka, context, greetings, rule = self.init_test().with_concepts(
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
create_new=True).with_format_rules(
Rule(predicate="recognize(__ret.body, hello sheerka)", action="")).unpack()
service = sheerka.services[SheerkaEvaluateRules.NAME]
ret = sheerka.ret("evaluator", True, sheerka.new(greetings, a=Expando("sheerka", {})))
res = service.evaluate_rules(context, [rule], {"__ret": ret}, set())
assert res == {True: [rule]}
@pytest.mark.skip("Not ready for that")
def test_i_can_evaluate_concept_rules_when_same_name(self):
sheerka, context, g1, g2, rule = self.init_test().with_concepts(
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
Concept("greetings", definition="hi a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
create_new=True).with_format_rules(
Rule(predicate="recognize(__ret.body, greetings)", action="")).unpack()
service = sheerka.services[SheerkaEvaluateRules.NAME]
ret1 = sheerka.ret("evaluator", True, sheerka.new(g1, a="kodjo"))
res = service.evaluate_rules(context, [rule], {"__ret": ret1}, set())
assert res == {True: [rule]}
ret2 = sheerka.ret("evaluator", True, sheerka.new(g2, a="kodjo"))
res = service.evaluate_rules(context, [rule], {"__ret": ret2}, set())
assert res == {True: [rule]}
def test_i_can_evaluate_concept_rule_with_the_same_name_when_the_second_concept_is_declared_after(self):
sheerka, context, g1, rule, g2 = self.init_test().with_concepts(
Concept("greetings", definition="hello a", definition_type=DEFINITION_TYPE_DEF).def_var("a"),
create_new=True).with_format_rules(Rule(predicate="recognize(__ret.body, greetings)", action="")).with_concepts(
Concept("greetings", definition="hi a", definition_type=DEFINITION_TYPE_DEF).def_var("a")).unpack()
service = sheerka.services[SheerkaEvaluateRules.NAME]
ret1 = sheerka.ret("evaluator", True, sheerka.new(g1, a="kodjo"))
res = service.evaluate_rules(context, [rule], {"__ret": ret1}, set())
assert res == {True: [rule]}
ret2 = sheerka.ret("evaluator", True, sheerka.new(g2, a="kodjo"))
res = service.evaluate_rules(context, [rule], {"__ret": ret2}, set())
assert res == {True: [rule]}
def test_i_can_disable_rules_at_runtime(self):
sheerka, context, r1, r2, = self.init_format_rules(
Rule(predicate="a == 1", action="", priority=2), # r1
Rule(predicate="a == 1", action="", priority=1), # r2
)
service = sheerka.services[SheerkaEvaluateRules.NAME]
rules = sorted([r1, r2], key=operator.attrgetter('priority'), reverse=True)
res = service.evaluate_rules(context, rules, {"a": 1}, {r1.id})
assert res == {
True: [r2],
DISABLED_RULES: [r1]
}
def test_rete_network_is_updated_on_new_rule_creation(self):
sheerka, context = self.init_test().unpack()
evaluate_rule_service = sheerka.services[SheerkaEvaluateRules.NAME]
rule_manager_service = sheerka.services[SheerkaRuleManager.NAME]
rule = Rule(ACTION_TYPE_EXEC, "test", "ret.status == True", "test()")
rule_manager_service.init_rule(context, rule)
sheerka.create_new_rule(context, rule)
assert rule in evaluate_rule_service.network.rules
assert rule.rete_net == evaluate_rule_service.network