import ast import pytest import core.utils from core.builtin_concepts import ParserResultConcept, BuiltinConcepts, ReturnValueConcept from core.concept import Concept from core.rule import Rule from core.sheerka.services.SheerkaExecute import ParserInput from core.tokenizer import Token, TokenKind, Tokenizer from parsers.BaseNodeParser import ConceptNode, UnrecognizedTokensNode, RuleNode from parsers.PythonParser import PythonNode from parsers.PythonWithConceptsParser import PythonWithConceptsParser from parsers.UnrecognizedNodeParser import UnrecognizedNodeParser from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka unrecognized_nodes_parser = UnrecognizedNodeParser() def ret_val(*args): result = [] index = 0 for item in args: if isinstance(item, Concept): tokens = [Token(TokenKind.IDENTIFIER, item.name, 0, 0, 0)] result.append(ConceptNode(item, index, index, tokens, item.name)) index += 1 elif isinstance(item, Rule): tokens = [Token(TokenKind.RULE, (None, item.id), 0, 0, 0)] result.append(RuleNode(item, index, index, tokens, f"r:|{item.id}:")) index += 1 else: tokens = list(Tokenizer(item)) result.append(UnrecognizedTokensNode(index, index + len(tokens) - 1, tokens)) index += len(tokens) return ReturnValueConcept("who", False, ParserResultConcept(parser=unrecognized_nodes_parser, value=result)) def to_str_ast(expression): return PythonNode.get_dump(ast.parse(expression, mode="eval")) class TestPythonWithConceptsParser(TestUsingMemoryBasedSheerka): @pytest.mark.parametrize("text, interested", [ ("not parser result", False), (ParserInput("not parser result"), False), (ParserResultConcept(parser="not multiple_concepts_parser"), False), (ParserResultConcept(parser=unrecognized_nodes_parser, value=[UnrecognizedTokensNode(0, 0, [])]), True), ]) def test_not_interested(self, text, interested): context = self.get_context() res = PythonWithConceptsParser().parse(context, text) if interested: assert res is not None else: assert res is None def test_i_can_parse_concepts_and_python(self): context = self.get_context() foo = Concept("foo") input_return_value = ret_val(foo, " + 1") parser = PythonWithConceptsParser() result = parser.parse(context, input_return_value.body) wrapper = result.value return_value = result.value.value assert result.status assert result.who == parser.name assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT) assert wrapper.source == "foo + 1" assert isinstance(return_value, PythonNode) assert return_value.source == "foo + 1" assert return_value.get_dump(return_value.ast_) == to_str_ast("__C__foo__C__ + 1") assert return_value.objects["__C__foo__C__"] == foo def test_i_can_parse_concepts_and_python_when_concept_is_known(self): context = self.get_context() foo = Concept("foo") foo = context.sheerka.create_new_concept(context, foo).body.body input_return_value = ret_val(foo, " + 1") parser = PythonWithConceptsParser() result = parser.parse(context, input_return_value.body) wrapper = result.value return_value = result.value.value assert result.status assert result.who == parser.name assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT) assert wrapper.source == "foo + 1" assert isinstance(return_value, PythonNode) assert return_value.source == "foo + 1" assert return_value.get_dump(return_value.ast_) == to_str_ast("__C__foo__1001__C__ + 1") assert return_value.objects["__C__foo__1001__C__"] == foo def test_i_can_parse_when_concept_name_has_invalid_characters(self): context = self.get_context() foo = Concept("foo et > (,") foo = context.sheerka.create_new_concept(context, foo).body.body input_return_value = ret_val(foo, " + 1") parser = PythonWithConceptsParser() result = parser.parse(context, input_return_value.body) return_value = result.value.value assert result.status assert return_value.objects["__C__foo0et000000__1001__C__"] == foo def test_i_can_parse_when_multiple_concepts(self): sheerka, context, foo, bar = self.init_concepts("foo", "bar") input_return_value = ret_val("func(", foo, ", ", bar, ")") parser = PythonWithConceptsParser() result = parser.parse(context, input_return_value.body) parser_result = result.value return_value = result.value.value assert result.status assert result.who == parser.name assert context.sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT) assert parser_result.source == "func(foo, bar)" assert isinstance(return_value, PythonNode) assert return_value.source == "func(foo, bar)" assert return_value.get_dump(return_value.ast_) == to_str_ast("func(__C__foo__1001__C__, __C__bar__1002__C__)") assert return_value.objects["__C__foo__1001__C__"] == foo assert return_value.objects["__C__bar__1002__C__"] == bar def test_i_can_parse_when_python_and_rule(self): context = self.get_context() rule = Rule().set_id("rule_id") input_return_value = ret_val(rule, " + 1") parser = PythonWithConceptsParser() result = parser.parse(context, input_return_value.body) wrapper = result.value return_value = result.value.value assert result.status assert result.who == parser.name assert context.sheerka.isinstance(wrapper, BuiltinConcepts.PARSER_RESULT) assert wrapper.source == "r:|rule_id: + 1" assert isinstance(return_value, PythonNode) assert return_value.source == "r:|rule_id: + 1" assert return_value.get_dump(return_value.ast_) == to_str_ast("__R____rule_id__R__ + 1") assert return_value.objects["__R____rule_id__R__"] == rule def test_python_ids_mappings_are_correct_when_rules_with_the_same_id(self): context = self.get_context() rule1 = Rule().set_id("rule_id") rule2 = Rule().set_id("rule_id") input_return_value = ret_val(rule1, "+", rule2) parser = PythonWithConceptsParser() result = parser.parse(context, input_return_value.body) return_value = result.value.value assert result.status assert return_value.objects["__R____rule_id__R__"] == rule1 assert return_value.objects["__R____rule_id_1__R__"] == rule2 def test_python_ids_mappings_are_correct_when_concepts_with_the_same_name(self): context = self.get_context() foo1 = Concept("foo") foo2 = Concept("foo") foo3 = context.sheerka.create_new_concept(context, Concept("foo", body="foo3")).body.body foo4 = context.sheerka.create_new_concept(context, Concept("foo", body="foo4")).body.body input_return_value = ret_val(foo1, "+", foo2, "+", foo3, "+", foo4) parser = PythonWithConceptsParser() result = parser.parse(context, input_return_value.body) return_value = result.value.value assert result.status assert return_value.objects["__C__foo__C__"] == foo1 assert return_value.objects["__C__foo_1__C__"] == foo2 assert return_value.objects["__C__foo__1001__C__"] == foo3 assert return_value.objects["__C__foo__1002__C__"] == foo4 def test_i_cannot_parse_if_syntax_error(self): context = self.get_context() foo = Concept("foo") foo = context.sheerka.create_new_concept(context, foo).body.body input_return_value = ret_val(foo, " + ") parser = PythonWithConceptsParser() result = parser.parse(context, input_return_value.body) assert not result.status assert context.sheerka.isinstance(result.value, BuiltinConcepts.NOT_FOR_ME)