@@ -0,0 +1,186 @@
|
||||
import pytest
|
||||
|
||||
from base import BaseTest
|
||||
from common.global_symbols import NotFound, NotInit
|
||||
from conftest import NewOntology
|
||||
from core.BuiltinConcepts import BuiltinConcepts
|
||||
from core.ErrorContext import ErrorContext
|
||||
from core.concept import ConceptMetadata
|
||||
from core.services.SheerkaConceptManager import ConceptAlreadyDefined, ConceptManager
|
||||
from helpers import get_metadata
|
||||
|
||||
|
||||
class TestConceptManager(BaseTest):
|
||||
|
||||
@pytest.fixture()
|
||||
def service(self, sheerka):
|
||||
return sheerka.services[ConceptManager.NAME]
|
||||
|
||||
def test_i_can_compute_concept_digest(self, service):
|
||||
"""
|
||||
Two concepts with the same definition share the same digest
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
metadata = get_metadata("foo", "body")
|
||||
digest = service.compute_metadata_digest(metadata)
|
||||
assert digest == "21a1c2f420da62f4dc60f600c95b19dd9527b19dd28fd38e17f5c0e28963d176"
|
||||
|
||||
another_metadata = get_metadata("foo", "body")
|
||||
other_digest = service.compute_metadata_digest(another_metadata)
|
||||
|
||||
assert digest == other_digest
|
||||
|
||||
def test_id_is_not_part_of_the_digest(self, service):
|
||||
metadata1 = get_metadata("foo", "body", id=1)
|
||||
metadata2 = get_metadata("foo", "body", id=2)
|
||||
|
||||
assert service.compute_metadata_digest(metadata1) == service.compute_metadata_digest(metadata2)
|
||||
|
||||
def test_i_can_compute_concept_attributes_based_on_the_metadata(self, service):
|
||||
compute_all_attrs = service.compute_all_attrs
|
||||
|
||||
m1 = get_metadata("foo")
|
||||
assert compute_all_attrs(m1.variables) == ('#where#', '#pre#', '#post#', '#body#', '#ret#')
|
||||
|
||||
m2 = get_metadata("bar", variables=[("var1", None), ("var2", None)])
|
||||
assert compute_all_attrs(m2.variables) == ('#where#', '#pre#', '#post#', '#body#', '#ret#', 'var1', 'var2')
|
||||
|
||||
@pytest.mark.parametrize("definition, variables, expected", [
|
||||
("foo", [], "foo"),
|
||||
("foo(bar)", [], "foo ( bar )"),
|
||||
("foo a", ["a"], "foo __var__0"),
|
||||
("a foo b", ["a", "b"], "__var__0 foo __var__1"),
|
||||
("a foo b", ["b", "a"], "__var__1 foo __var__0"),
|
||||
("foo", ["foo"], "foo"),
|
||||
("foo a", ["foo"], "__var__0 a"),
|
||||
("foo a b", ["a"], "foo __var__0 b"),
|
||||
("'foo'", [], "'foo'"),
|
||||
("my name is a", ["a"], "my name is __var__0"),
|
||||
("a b c d", ["b", "c"], "a __var__0 __var__1 d"),
|
||||
("a 'b c' d", ["b", "c"], "a 'b c' d"),
|
||||
("a | b", ["a", "b"], "__var__0 | __var__1"),
|
||||
("a b a c", ["a", "b"], "__var__0 __var__1 __var__0 c"),
|
||||
("a b a c", ["b", "a"], "__var__1 __var__0 __var__1 c"),
|
||||
("def concept a", ["a"], "def concept __var__0"),
|
||||
])
|
||||
def test_i_can_create_concept_key(self, service, definition, variables, expected):
|
||||
expanded_variables = tuple((v, NotInit) for v in variables)
|
||||
key = service.create_concept_key(definition, None, expanded_variables)
|
||||
|
||||
assert key == expected
|
||||
|
||||
def test_the_key_is_created_from_the_definition_if_it_is_set(self, service):
|
||||
assert service.create_concept_key("from name", "from definition", None) == "from definition"
|
||||
assert service.create_concept_key("from name", None, None) == "from name"
|
||||
|
||||
def test_i_can_define_a_new_concept(self, context, service):
|
||||
with NewOntology(context, "test_i_can_define_a_new_concept"):
|
||||
res = service.define_new_concept(context, "name", body="body")
|
||||
|
||||
assert res.status is True
|
||||
|
||||
metadata = res.value.metadata
|
||||
assert isinstance(metadata, ConceptMetadata)
|
||||
assert metadata.id == "1001"
|
||||
assert metadata.name == "name"
|
||||
assert metadata.key == "name"
|
||||
assert metadata.body == "body"
|
||||
assert metadata.digest == "eb0620bd4a317af8a403c0ae1e185a528f9b58f8b0878d990e62278f89cf10d5"
|
||||
assert metadata.all_attrs == ('#where#', '#pre#', '#post#', '#body#', '#ret#')
|
||||
|
||||
# is sorted in db
|
||||
om = context.sheerka.om
|
||||
assert om.get(ConceptManager.CONCEPTS_BY_ID_ENTRY, metadata.id) == metadata
|
||||
assert om.get(ConceptManager.CONCEPTS_BY_NAME_ENTRY, metadata.name) == metadata
|
||||
assert om.get(ConceptManager.CONCEPTS_BY_KEY_ENTRY, metadata.key) == metadata
|
||||
assert om.get(ConceptManager.CONCEPTS_BY_HASH_ENTRY, metadata.digest) == metadata
|
||||
|
||||
def test_i_cannot_create_the_same_concept_twice(self, context, service):
|
||||
with NewOntology(context, "test_i_cannot_create_the_same_concept_twice"):
|
||||
res = service.define_new_concept(context, "name", body="body")
|
||||
assert res.status
|
||||
|
||||
res = service.define_new_concept(context, "name", body="body")
|
||||
assert not res.status
|
||||
assert isinstance(res.value, ErrorContext)
|
||||
assert isinstance(res.value.value, ConceptAlreadyDefined)
|
||||
|
||||
def test_i_can_add_the_same_concept_on_different_ontologies(self, context, service):
|
||||
with NewOntology(context, "test_i_can_add_the_same_concept_on_different_ontologies"):
|
||||
res = service.define_new_concept(context, "name", body="body")
|
||||
assert res.status
|
||||
|
||||
sheerka = context.sheerka
|
||||
om = sheerka.om
|
||||
om.push_ontology("my_new_ontology")
|
||||
res = service.define_new_concept(context, "name", body="body")
|
||||
assert res.status is True
|
||||
|
||||
def test_i_can_get_a_newly_created_concept(self, context, service):
|
||||
with NewOntology(context, "test_i_can_get_a_newly_created_concept"):
|
||||
res = service.define_new_concept(context, "name", body="body")
|
||||
assert res.status
|
||||
metadata = res.value.metadata
|
||||
|
||||
assert service.get_by_id(metadata.id).id == metadata.id
|
||||
assert service.get_by_name(metadata.name).name == metadata.name
|
||||
assert service.get_by_key(metadata.key).key == metadata.key
|
||||
|
||||
def test_i_can_instantiate_a_new_concept_by_its_name(self, context, service):
|
||||
with NewOntology(context, "test_i_can_instantiate_a_new_concept_by_its_name"):
|
||||
res = service.define_new_concept(context, "foo", variables=[("var1", None), ("var2", None)])
|
||||
assert res.status
|
||||
|
||||
foo = service.newn("foo", var1="value1", var2="value2")
|
||||
|
||||
assert foo.id == "1001"
|
||||
assert foo.key == "foo"
|
||||
assert foo.name == "foo"
|
||||
assert foo.str_id == "c:#1001:"
|
||||
assert foo.var1 == "value1"
|
||||
assert foo.var2 == "value2"
|
||||
|
||||
def test_i_can_instantiate_a_new_concept_by_its_id(self, context, service):
|
||||
with NewOntology(context, "test_i_can_instantiate_a_new_concept_by_its_id"):
|
||||
res = service.define_new_concept(context, "foo", variables=[("var1", None), ("var2", None)])
|
||||
assert res.status
|
||||
|
||||
foo = service.newi("1001", var1="value1", var2="value2")
|
||||
|
||||
assert foo.id == "1001"
|
||||
assert foo.key == "foo"
|
||||
assert foo.name == "foo"
|
||||
assert foo.str_id == "c:#1001:"
|
||||
assert foo.var1 == "value1"
|
||||
assert foo.var2 == "value2"
|
||||
|
||||
def test_i_cannot_instantiate_a_concept_which_does_not_exist(self, context, service):
|
||||
foo = service.newn("foo", var1="value1", var2="value2")
|
||||
assert foo.key == BuiltinConcepts.UNKNOWN_CONCEPT
|
||||
assert foo.requested_name == "foo"
|
||||
|
||||
foo = service.newi("1001", var1="value1", var2="value2")
|
||||
assert foo.key == BuiltinConcepts.UNKNOWN_CONCEPT
|
||||
assert foo.requested_id == "1001"
|
||||
|
||||
def test_i_can_instantiate_by_name_when_multiple_results(self, context, service):
|
||||
with NewOntology(context, "test_i_can_instantiate_by_name_when_multiple_results"):
|
||||
service.define_new_concept(context, "foo", body="body1")
|
||||
service.define_new_concept(context, "foo", body="body2")
|
||||
|
||||
concepts = service.newn("foo")
|
||||
|
||||
assert len(concepts) == 2
|
||||
assert concepts[0].id == "1001"
|
||||
assert concepts[0].get_metadata().body == "body1"
|
||||
assert concepts[1].id == "1002"
|
||||
assert concepts[1].get_metadata().body == "body2"
|
||||
|
||||
def test_concepts_are_removed_when_ontology_is_popped(self, context, service):
|
||||
context.sheerka.om.push_ontology("new ontology")
|
||||
res = service.define_new_concept(context, "foo", body="body")
|
||||
assert service.get_by_id(res.value.metadata.id) is not NotFound
|
||||
|
||||
context.sheerka.om.pop_ontology(context)
|
||||
assert service.get_by_id(res.value.metadata.id) is NotFound
|
||||
@@ -0,0 +1,379 @@
|
||||
from typing import Callable
|
||||
|
||||
import pytest
|
||||
|
||||
from base import BaseTest
|
||||
from core.BuiltinConcepts import BuiltinConcepts
|
||||
from core.ExecutionContext import ExecutionContext, ExecutionContextActions
|
||||
from core.ReturnValue import ReturnValue
|
||||
from core.services.SheerkaEngine import SheerkaEngine
|
||||
from evaluators.CreateParserInput import CreateParserInput
|
||||
from evaluators.base_evaluator import AllReturnValuesEvaluator, BaseEvaluator, EvaluatorEvalResult, \
|
||||
EvaluatorMatchResult, \
|
||||
OneReturnValueEvaluator
|
||||
from helpers import _rvc
|
||||
|
||||
ALL_STEPS = [
|
||||
ExecutionContextActions.BEFORE_PARSING,
|
||||
ExecutionContextActions.PARSING,
|
||||
ExecutionContextActions.AFTER_PARSING,
|
||||
ExecutionContextActions.BEFORE_EVALUATION,
|
||||
ExecutionContextActions.EVALUATION,
|
||||
ExecutionContextActions.AFTER_EVALUATION
|
||||
]
|
||||
|
||||
|
||||
class OneReturnValueEvaluatorForTesting(OneReturnValueEvaluator):
|
||||
def __init__(self, name,
|
||||
step: ExecutionContextActions,
|
||||
priority: int,
|
||||
enabled=True,
|
||||
match: bool | Callable = True,
|
||||
match_context=None,
|
||||
eval_result: list[ReturnValue] = None,
|
||||
eval_eaten: list[ReturnValue] = None):
|
||||
super().__init__(name, step, priority, enabled)
|
||||
self.matches_delegate = match
|
||||
self.matches_context = match_context
|
||||
self.eval_result = eval_result
|
||||
self.eval_eaten = eval_eaten
|
||||
|
||||
def matches(self, context: ExecutionContext, return_value: ReturnValue) -> EvaluatorMatchResult:
|
||||
# if status is a bool, use it
|
||||
# otherwise, it's a delegate, so apply to return_value
|
||||
status = self.matches_delegate if \
|
||||
isinstance(self.matches_delegate, bool) else \
|
||||
self.matches_delegate(return_value)
|
||||
return EvaluatorMatchResult(status, self.matches_context)
|
||||
|
||||
def eval(self, context: ExecutionContext,
|
||||
evaluation_context: object,
|
||||
return_value: ReturnValue) -> EvaluatorEvalResult:
|
||||
|
||||
# make sure to correctly set up the parent when the return value is modified
|
||||
if self.eval_result:
|
||||
for ret_val in self.eval_result:
|
||||
if ret_val != return_value:
|
||||
ret_val.parents = [return_value]
|
||||
|
||||
return EvaluatorEvalResult(self.eval_result, self.eval_eaten or [return_value])
|
||||
|
||||
|
||||
class AllReturnValuesEvaluatorForTesting(AllReturnValuesEvaluator):
|
||||
def __init__(self, name,
|
||||
step: ExecutionContextActions,
|
||||
priority: int,
|
||||
enabled=True,
|
||||
match: bool | Callable = True,
|
||||
match_context=None,
|
||||
eval_result: list[ReturnValue] = None,
|
||||
eval_eaten: list[ReturnValue] = None):
|
||||
super().__init__(name, step, priority, enabled)
|
||||
self.matches_delegate = match
|
||||
self.matches_context = match_context
|
||||
self.eval_result = eval_result
|
||||
self.eval_eaten = eval_eaten
|
||||
|
||||
def matches(self, context: ExecutionContext, return_values: list[ReturnValue]) -> EvaluatorMatchResult:
|
||||
# if status is a bool, use it
|
||||
# otherwise, it's a delegate, so apply to return_value
|
||||
status = self.matches_delegate if \
|
||||
isinstance(self.matches_delegate, bool) else \
|
||||
self.matches_delegate(return_values)
|
||||
return EvaluatorMatchResult(status, self.matches_context)
|
||||
|
||||
def eval(self, context: ExecutionContext,
|
||||
evaluation_context: object,
|
||||
return_values: list[ReturnValue]) -> EvaluatorEvalResult:
|
||||
|
||||
# make sure to correctly set up the parent when the return value is modified
|
||||
if self.eval_result:
|
||||
for ret_val in self.eval_result:
|
||||
ret_val.parents = return_values
|
||||
|
||||
return EvaluatorEvalResult(self.eval_result, self.eval_eaten or return_values)
|
||||
|
||||
|
||||
class TestSheerkaEngine(BaseTest):
|
||||
@pytest.fixture()
|
||||
def service(self, sheerka):
|
||||
return SheerkaEngine(sheerka)
|
||||
|
||||
def test_i_can_compute_execution_plan(self, service):
|
||||
assert service.compute_execution_plan([]) == {}
|
||||
|
||||
e1 = BaseEvaluator("eval1", ExecutionContextActions.BEFORE_EVALUATION, 5)
|
||||
e2 = BaseEvaluator("eval2", ExecutionContextActions.BEFORE_EVALUATION, 5)
|
||||
e3 = BaseEvaluator("eval3", ExecutionContextActions.BEFORE_EVALUATION, 10)
|
||||
e4 = BaseEvaluator("eval4", ExecutionContextActions.EVALUATION, 10)
|
||||
e5 = BaseEvaluator("eval5", ExecutionContextActions.AFTER_EVALUATION, 10, enabled=False)
|
||||
res = service.compute_execution_plan([e1, e2, e3, e4, e5])
|
||||
assert res == {ExecutionContextActions.BEFORE_EVALUATION: {5: [e1, e2], 10: [e3]},
|
||||
ExecutionContextActions.EVALUATION: {10: [e4]}}
|
||||
|
||||
def test_i_can_call_execute(self, sheerka, context, service):
|
||||
service.execution_plan = {ExecutionContextActions.BEFORE_EVALUATION: {50: [CreateParserInput()]}}
|
||||
start = [ReturnValue("TestSheerkaEngine", True, sheerka.newn(BuiltinConcepts.USER_INPUT, command="1 + 1"))]
|
||||
|
||||
ret = service.execute(context, start, [ExecutionContextActions.BEFORE_EVALUATION])
|
||||
assert len(ret) == 1
|
||||
ret = ret[0]
|
||||
assert isinstance(ret, ReturnValue)
|
||||
assert ret.who == CreateParserInput.NAME
|
||||
assert ret.status is True
|
||||
assert ret.parents == start
|
||||
|
||||
def test_that_return_values_is_unchanged_when_no_evaluator(self, context, service):
|
||||
service.execution_plan = {}
|
||||
start = [_rvc("foo")]
|
||||
|
||||
ret = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
|
||||
assert ret == start
|
||||
|
||||
def test_steps_are_executed_in_correct_order(self, context, service):
|
||||
# properly init the service
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1", ExecutionContextActions.AFTER_PARSING, 21, match=False),
|
||||
_("eval2", ExecutionContextActions.BEFORE_EVALUATION, 5, match=False),
|
||||
_("eval3", ExecutionContextActions.AFTER_EVALUATION, 12, match=False),
|
||||
_("eval4", ExecutionContextActions.EVALUATION, 99, match=False),
|
||||
_("eval5", ExecutionContextActions.BEFORE_PARSING, 5, match=False),
|
||||
_("eval6", ExecutionContextActions.PARSING, 25, match=False),
|
||||
]
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
# init test variables
|
||||
start = [_rvc("foo")]
|
||||
service.execute(context, start, ALL_STEPS)
|
||||
# to check what happened, look at the execution context children
|
||||
executed_steps = [ec.action_context["step"] for ec in context.get_children(level=1)]
|
||||
assert executed_steps == ALL_STEPS
|
||||
|
||||
def test_higher_priority_evaluators_are_executed_first(self, context, service):
|
||||
# properly init the service
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1", ExecutionContextActions.EVALUATION, 20, match=False),
|
||||
_("eval2", ExecutionContextActions.EVALUATION, 5, match=False),
|
||||
_("eval3", ExecutionContextActions.EVALUATION, 20, match=False),
|
||||
_("eval4", ExecutionContextActions.EVALUATION, 99, match=False),
|
||||
]
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [_rvc("foo")]
|
||||
service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
|
||||
# to check what happened, look at the execution context children
|
||||
evaluators_executed = [ec.action_context["evaluator"] for ec in context.get_children() if
|
||||
"evaluator" in ec.action_context]
|
||||
assert evaluators_executed == ["eval4", "eval1", "eval3", "eval2"]
|
||||
|
||||
def test_evaluation_loop_stops_when_no_modification(self, context, service):
|
||||
rv_foo, rv_bar = _rvc("foo"), _rvc("bar") # rv => ReturnValue
|
||||
# properly init the service
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[rv_bar])
|
||||
]
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [rv_foo]
|
||||
service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
children = [ec for ec in context.get_children() if ec.action == ExecutionContextActions.EVALUATING_ITERATION]
|
||||
assert len(children) == 2
|
||||
|
||||
def test_eval_is_not_called_if_match_fails_for_one_return(self, context, service):
|
||||
# properly init the service
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[_rvc("bar")])
|
||||
]
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [_rvc("baz")]
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
assert res == start
|
||||
|
||||
# check what happen in details
|
||||
exec_context = next(filter(lambda ec: "evaluator" in ec.action_context, context.get_children()))
|
||||
evaluation_trace = exec_context.values["evaluation"]
|
||||
assert evaluation_trace == [{"item": start[0], "match": False}]
|
||||
|
||||
def test_eval_is_called_if_match_succeed_for_one_return(self, context, service):
|
||||
# properly init the service
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[_rvc("bar")])
|
||||
]
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [_rvc("foo")]
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
assert res == [_rvc("bar")]
|
||||
assert res[0].parents == start
|
||||
|
||||
# check what happen in details
|
||||
exec_context = next(filter(lambda ec: "evaluator" in ec.action_context, context.get_children()))
|
||||
evaluation_trace = exec_context.values["evaluation"]
|
||||
assert evaluation_trace == [{"item": start[0], "match": True, "new": res, "eaten": start}]
|
||||
|
||||
def test_all_item_are_processed_during_one_return(self, context, service):
|
||||
rv_foo, rv_bar, rv_baz, rv_qux = _rvc("foo"), _rvc("bar"), _rvc("baz"), _rvc("qux") # rv => ReturnValue
|
||||
|
||||
# properly init the service
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[rv_qux])
|
||||
]
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [rv_bar, rv_foo, rv_baz]
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
assert res == [rv_bar, rv_qux, rv_baz] # We must keep the order ! rv_qux replaces rv_foo
|
||||
assert res[0].parents is None
|
||||
assert res[1].parents == [rv_foo]
|
||||
assert res[2].parents is None
|
||||
|
||||
# check what happen in details
|
||||
exec_context = next(filter(lambda ec: "evaluator" in ec.action_context, context.get_children()))
|
||||
evaluation_trace = exec_context.values["evaluation"]
|
||||
assert evaluation_trace == [{"item": rv_bar, "match": False},
|
||||
{"item": rv_foo, "match": True, "new": [rv_qux], "eaten": [rv_foo]},
|
||||
{"item": rv_baz, "match": False}]
|
||||
|
||||
def test_evaluators_with_the_same_priority_do_not_compete_with_each_other_one_return(self, context, service):
|
||||
rv_foo, rv_bar, rv_baz, rv_qux = _rvc("foo"), _rvc("bar"), _rvc("baz"), _rvc("qux") # rv => ReturnValue
|
||||
|
||||
# properly init the service
|
||||
# both evaluator want to eat 'foo'
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[rv_bar]),
|
||||
_("eval2",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[rv_baz])
|
||||
]
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [rv_qux, rv_foo, rv_qux]
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
assert res == [rv_qux, rv_bar, rv_baz, rv_qux] # they both eat it !
|
||||
assert res[1].parents == [rv_foo]
|
||||
assert res[2].parents == [rv_foo]
|
||||
|
||||
def test_evaluators_with_higher_priority_take_precedence_one_return(self, context, service):
|
||||
rv_foo, rv_bar, rv_baz = _rvc("foo"), _rvc("bar"), _rvc("baz") # rv => ReturnValue
|
||||
|
||||
# properly init the service
|
||||
# both evaluator want to eat 'foo'
|
||||
_ = OneReturnValueEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[rv_bar]),
|
||||
_("eval2",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
30,
|
||||
match=lambda r: context.sheerka.isinstance(r.value, "foo"),
|
||||
eval_result=[rv_baz])
|
||||
]
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [rv_foo]
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
assert res == [rv_baz]
|
||||
assert res[0].parents == start
|
||||
|
||||
def test_evaluator_matches_is_called_before_eval_for_all_return(self, context, service):
|
||||
# properly init the service
|
||||
_ = AllReturnValuesEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda r: context.sheerka.isinstance(r[0].value, "foo"),
|
||||
eval_result=[_rvc("bar")])
|
||||
]
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [_rvc("baz")]
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
assert res == start
|
||||
|
||||
start = [_rvc("foo")]
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
assert res == [_rvc("bar")]
|
||||
assert res[0].parents == start
|
||||
|
||||
def test_eval_is_not_call_if_match_fails_for_all_return(self, context, service):
|
||||
rv_foo, rv_bar, rv_baz = _rvc("foo"), _rvc("bar"), _rvc("baz") # rv => ReturnValue
|
||||
|
||||
# properly init the service
|
||||
_ = AllReturnValuesEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda lst: context.sheerka.isinstance(lst[0].value, "foo"),
|
||||
eval_result=[rv_bar])
|
||||
]
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [rv_baz, rv_foo] # foo is not the first in the list
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
assert res == start
|
||||
|
||||
# check what happen in details
|
||||
exec_context = next(filter(lambda ec: "evaluator" in ec.action_context, context.get_children()))
|
||||
evaluation_trace = exec_context.values["evaluation"]
|
||||
assert evaluation_trace == {"match": False}
|
||||
|
||||
def test_eval_is_called_if_match_succeed_for_all_return(self, context, service):
|
||||
rv_foo, rv_bar, rv_baz = _rvc("foo"), _rvc("bar"), _rvc("baz") # rv => ReturnValue
|
||||
# properly init the service
|
||||
_ = AllReturnValuesEvaluatorForTesting
|
||||
evaluators = [
|
||||
_("eval1",
|
||||
ExecutionContextActions.EVALUATION,
|
||||
20,
|
||||
match=lambda lst: context.sheerka.isinstance(lst[0].value, "foo"),
|
||||
eval_result=[rv_bar])
|
||||
]
|
||||
service.execution_plan = service.compute_execution_plan(evaluators)
|
||||
|
||||
start = [rv_foo, rv_baz]
|
||||
res = service.execute(context, start, [ExecutionContextActions.EVALUATION])
|
||||
assert res == [rv_bar]
|
||||
assert res[0].parents == start
|
||||
|
||||
children = list(context.get_children())
|
||||
# check what happen in details
|
||||
exec_context = next(filter(lambda ec: "evaluator" in ec.action_context, context.get_children()))
|
||||
evaluation_trace = exec_context.values["evaluation"]
|
||||
assert evaluation_trace == {"match": True, "new": res, "eaten": start}
|
||||
Reference in New Issue
Block a user