Working on #50 : Adding unit tests
This commit is contained in:
@@ -17,11 +17,12 @@ from core.tokenizer import Keywords, TokenKind, Token, IterParser
|
|||||||
from core.utils import index_tokens, COLORS, get_text_from_tokens
|
from core.utils import index_tokens, COLORS, get_text_from_tokens
|
||||||
from evaluators.ConceptEvaluator import ConceptEvaluator
|
from evaluators.ConceptEvaluator import ConceptEvaluator
|
||||||
from evaluators.PythonEvaluator import PythonEvaluator, Expando
|
from evaluators.PythonEvaluator import PythonEvaluator, Expando
|
||||||
|
from parsers.BaseExpressionParser import AndNode, ExpressionVisitor, VariableNode, ComparisonNode
|
||||||
from parsers.BaseNodeParser import SourceCodeWithConceptNode, ConceptNode, SourceCodeNode
|
from parsers.BaseNodeParser import SourceCodeWithConceptNode, ConceptNode, SourceCodeNode
|
||||||
from parsers.LogicalOperatorParser import LogicalOperatorParser
|
from parsers.LogicalOperatorParser import LogicalOperatorParser
|
||||||
from parsers.PythonParser import PythonNode
|
from parsers.PythonParser import PythonNode
|
||||||
from parsers.BaseExpressionParser import AndNode
|
from sheerkarete.common import V
|
||||||
from sheerkarete.conditions import AndConditions
|
from sheerkarete.conditions import AndConditions, Condition
|
||||||
|
|
||||||
CONCEPTS_ONLY_PARSERS = ["ExactConcept", "Bnf", "Sya", "Sequence"]
|
CONCEPTS_ONLY_PARSERS = ["ExactConcept", "Bnf", "Sya", "Sequence"]
|
||||||
|
|
||||||
@@ -1118,3 +1119,51 @@ class SheerkaRuleManager(BaseService):
|
|||||||
return return_value.body.body.concept
|
return return_value.body.body.concept
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class ReteConditionExprVisitor(ExpressionVisitor):
|
||||||
|
|
||||||
|
def __init__(self, context):
|
||||||
|
self.context = context
|
||||||
|
self.var_counter = 0
|
||||||
|
self.variables = {}
|
||||||
|
self.res = []
|
||||||
|
|
||||||
|
def add_variable(self, target):
|
||||||
|
var_name = f"__x_{self.var_counter:02}__"
|
||||||
|
self.var_counter += 1
|
||||||
|
self.variables[target] = var_name
|
||||||
|
return var_name
|
||||||
|
|
||||||
|
def init_variable_if_needed(self, node):
|
||||||
|
if node.name not in self.variables:
|
||||||
|
var_name = self.add_variable(node.name)
|
||||||
|
self.res.append(Condition(V(var_name), "__name__", node.name))
|
||||||
|
|
||||||
|
return V(self.variables[node.name])
|
||||||
|
|
||||||
|
def get_conditions(self, expr_node):
|
||||||
|
self.res.clear()
|
||||||
|
self.var_counter = 0
|
||||||
|
self.variables.clear()
|
||||||
|
|
||||||
|
self.visit(expr_node)
|
||||||
|
return AndConditions(self.res)
|
||||||
|
|
||||||
|
def visit_VariableNode(self, expr_node):
|
||||||
|
var_name = self.init_variable_if_needed(expr_node)
|
||||||
|
if expr_node.attributes_str is not None:
|
||||||
|
self.res.append(Condition(var_name, expr_node.attributes_str, True))
|
||||||
|
|
||||||
|
def visit_AndNode(self, expr_node: AndNode):
|
||||||
|
for node in expr_node.parts:
|
||||||
|
self.visit(node)
|
||||||
|
|
||||||
|
def visit_ComparisonNode(self, expr_node: ComparisonNode):
|
||||||
|
if isinstance(expr_node.left, VariableNode):
|
||||||
|
left = self.init_variable_if_needed(expr_node.left)
|
||||||
|
attr = expr_node.left.attributes_str or "__self__"
|
||||||
|
right = eval(get_text_from_tokens(expr_node.right.tokens))
|
||||||
|
self.res.append(Condition(left, attr, right))
|
||||||
|
else:
|
||||||
|
raise FailedToCompileError(expr_node)
|
||||||
|
|||||||
@@ -7,20 +7,23 @@ from core.concept import Concept, DEFINITION_TYPE_DEF, DoNotResolve
|
|||||||
from core.global_symbols import RULE_COMPARISON_CONTEXT, NotFound, EVENT_RULE_DELETED
|
from core.global_symbols import RULE_COMPARISON_CONTEXT, NotFound, EVENT_RULE_DELETED
|
||||||
from core.rule import Rule, ACTION_TYPE_PRINT, ACTION_TYPE_EXEC
|
from core.rule import Rule, ACTION_TYPE_PRINT, ACTION_TYPE_EXEC
|
||||||
from core.sheerka.Sheerka import RECOGNIZED_BY_ID, RECOGNIZED_BY_NAME
|
from core.sheerka.Sheerka import RECOGNIZED_BY_ID, RECOGNIZED_BY_NAME
|
||||||
|
from core.sheerka.services.SheerkaExecute import ParserInput
|
||||||
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, FormatRuleActionParser, \
|
from core.sheerka.services.SheerkaRuleManager import SheerkaRuleManager, FormatRuleActionParser, \
|
||||||
FormatAstRawText, FormatAstVariable, FormatAstSequence, FormatAstFunction, \
|
FormatAstRawText, FormatAstVariable, FormatAstSequence, FormatAstFunction, \
|
||||||
FormatRuleSyntaxError, FormatAstList, UnexpectedEof, FormatAstColor, RuleCompiledPredicate, FormatAstDict, \
|
FormatRuleSyntaxError, FormatAstList, UnexpectedEof, FormatAstColor, RuleCompiledPredicate, FormatAstDict, \
|
||||||
FormatAstMulti, \
|
FormatAstMulti, \
|
||||||
PythonCodeEmitter, NoConditionFound, FormatAstNode
|
PythonCodeEmitter, NoConditionFound, FormatAstNode, ReteConditionExprVisitor
|
||||||
from core.sheerka.services.sheerka_service import FailedToCompileError
|
from core.sheerka.services.sheerka_service import FailedToCompileError
|
||||||
from core.tokenizer import Token, TokenKind
|
from core.tokenizer import Token, TokenKind
|
||||||
from parsers.BaseNodeParser import SourceCodeWithConceptNode, SourceCodeNode
|
from parsers.BaseNodeParser import SourceCodeWithConceptNode, SourceCodeNode
|
||||||
|
from parsers.BaseParser import ErrorSink
|
||||||
|
from parsers.ExpressionParser import ExpressionParser
|
||||||
from parsers.PythonParser import PythonNode
|
from parsers.PythonParser import PythonNode
|
||||||
from sheerkarete.common import V
|
from sheerkarete.common import V
|
||||||
from sheerkarete.conditions import Condition, AndConditions
|
from sheerkarete.conditions import Condition, AndConditions
|
||||||
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
|
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
|
||||||
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
||||||
from tests.parsers.parsers_utils import CMV, CC, compare_with_test_object, get_test_obj
|
from tests.parsers.parsers_utils import CMV, CC, compare_with_test_object, get_test_obj, get_rete_conditions
|
||||||
|
|
||||||
seq = FormatAstSequence
|
seq = FormatAstSequence
|
||||||
raw = FormatAstRawText
|
raw = FormatAstRawText
|
||||||
@@ -1007,6 +1010,39 @@ isinstance(var, Concept) and var.key == 'hello __var__0'""" + \
|
|||||||
for k, v in vars(rule).items():
|
for k, v in vars(rule).items():
|
||||||
assert getattr(clone, k) == getattr(rule, k)
|
assert getattr(clone, k) == getattr(rule, k)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("expression, expected_as_str", [
|
||||||
|
(
|
||||||
|
"__ret",
|
||||||
|
["#__x_00__|__name__|'__ret'"],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"__ret.status == True",
|
||||||
|
["#__x_00__|__name__|'__ret'", "#__x_00__|status|True"],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"__ret.status",
|
||||||
|
["#__x_00__|__name__|'__ret'", "#__x_00__|status|True"],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"__ret and __ret.status",
|
||||||
|
["#__x_00__|__name__|'__ret'", "#__x_00__|status|True"],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
def test_i_can_get_rete_conditions(self, expression, expected_as_str):
|
||||||
|
sheerka, context, = self.init_test().unpack()
|
||||||
|
parser = ExpressionParser()
|
||||||
|
expected = get_rete_conditions(*expected_as_str)
|
||||||
|
|
||||||
|
error_sink = ErrorSink()
|
||||||
|
parser_input = ParserInput(expression)
|
||||||
|
parser.reset_parser_input(parser_input, error_sink)
|
||||||
|
parsed = parser.parse_input(context, parser_input, error_sink)
|
||||||
|
|
||||||
|
visitor = ReteConditionExprVisitor(context)
|
||||||
|
conditions = visitor.get_conditions(parsed)
|
||||||
|
|
||||||
|
assert conditions == expected
|
||||||
|
|
||||||
|
|
||||||
class TestSheerkaRuleManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
|
class TestSheerkaRuleManagerUsingFileBasedSheerka(TestUsingFileBasedSheerka):
|
||||||
def test_rules_are_initialized_at_startup(self):
|
def test_rules_are_initialized_at_startup(self):
|
||||||
|
|||||||
@@ -54,7 +54,8 @@ class TestExpressionParser(TestUsingMemoryBasedSheerka):
|
|||||||
("func(var.attr)", FN("func(", ")", [VAR("var.attr")])),
|
("func(var.attr)", FN("func(", ")", [VAR("var.attr")])),
|
||||||
("func(var1.attr1 and var2.attr2)", FN("func(", ")", [AND(VAR("var1.attr1"), VAR("var2.attr2"))])),
|
("func(var1.attr1 and var2.attr2)", FN("func(", ")", [AND(VAR("var1.attr1"), VAR("var2.attr2"))])),
|
||||||
("func(var1.attr1 > var2.attr2)", FN("func(", ")", [GT(VAR("var1.attr1"), VAR("var2.attr2"))])),
|
("func(var1.attr1 > var2.attr2)", FN("func(", ")", [GT(VAR("var1.attr1"), VAR("var2.attr2"))])),
|
||||||
("func1(var1) and func2(var2)", AND(FN("func1(", ")", [VAR("var1")]), FN("func2(", (")", 1), [VAR("var2")])))
|
("func1(var1) and func2(var2)", AND(FN("func1(", ")", [VAR("var1")]), FN("func2(", (")", 1), [VAR("var2")]))),
|
||||||
|
("__ret", VAR("__ret")),
|
||||||
])
|
])
|
||||||
def test_i_can_parse_input(self, expression, expected):
|
def test_i_can_parse_input(self, expression, expected):
|
||||||
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
|
sheerka, context, parser, parser_input, error_sink = self.init_parser_with_source(expression)
|
||||||
|
|||||||
Reference in New Issue
Block a user