Working on #50 : Adding unit tests

This commit is contained in:
2021-03-12 14:14:17 +01:00
parent ba9ba5bcb3
commit 42bc6abf97
3 changed files with 91 additions and 5 deletions
@@ -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)
+38 -2
View File
@@ -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):
+2 -1
View File
@@ -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)