import pytest from core.builtin_concepts import BuiltinConcepts from core.concept import Concept from core.sheerka.services.SheerkaExecute import ParserInput from parsers.BaseNodeParser import SCN, SCWC, CN, UTN, CNC from parsers.FunctionParser import FunctionParser, FN from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka from tests.parsers.parsers_utils import compute_expected_array cmap = { "one": Concept("one"), "two": Concept("two"), "twenties": Concept("twenties", definition="'twenty' (one|two)=unit").def_var("unit"), "plus": Concept("a plus b").def_var("a").def_var("b"), } class TestFunctionParser(TestUsingMemoryBasedSheerka): sheerka = None @classmethod def setup_class(cls): t = cls() cls.sheerka, context, _ = t.init_parser(cmap) def init_parser(self, concepts_map=None): if concepts_map is not None: sheerka, context, *concepts = self.init_concepts(*concepts_map.values(), create_new=True) else: sheerka = TestFunctionParser.sheerka context = self.get_context(sheerka) parser = FunctionParser() return sheerka, context, parser def test_i_can_detect_empty_expression(self): sheerka, context, parser = self.init_parser() res = parser.parse(context, ParserInput("")) assert not res.status assert sheerka.isinstance(res.body, BuiltinConcepts.IS_EMPTY) def test_input_must_be_a_parser_input(self): sheerka, context, parser = self.init_parser() parser.parse(context, "not a parser input") is None def test_i_cannot_parse_when_not_a_function(self): sheerka, context, parser = self.init_parser() res = parser.parse(context, ParserInput("not a function")) assert not res.status assert sheerka.isinstance(res.body, BuiltinConcepts.NOT_FOR_ME) @pytest.mark.parametrize("expression, expected", [ ("func()", FN("func(", ")", [])), ("concept(one)", FN("concept(", ")", ["one"])), ("func(one)", FN("func(", ")", ["one"])), ("func(a long two, 'three', ;:$*)", FN("func(", ")", ["a long two, ", "'three', ", ";:$*"])), ("func(func1(one), two, func2(func3(), func4(three)))", FN("func(", ")", [ (FN("func1(", ")", ["one"]), ", "), "two, ", (FN("func2(", ")", [ (FN("func3(", ")", []), ", "), (FN("func4(", ")", ["three"]), None), ]), None) ])), ]) def test_i_can_parse_function(self, expression, expected): sheerka, context, parser = self.init_parser() parser.reset_parser(context, ParserInput(expression)) res = parser.parse_function() assert res == expected @pytest.mark.parametrize("text, expected", [ ("func()", SCN("func()")), (" func()", SCN("func()")), ("func(one)", SCWC("func(", ")", CN("one"))), ("func(one, unknown, two)", SCWC("func(", ")", CN("one"), ", ", UTN("unknown"), (", ", 1), CN("two"))), ("func(one, twenty two)", SCWC("func(", ")", "one", ", ", CN("twenties", source="twenty two"))), ("func(one plus two, three)", SCWC("func(", ")", CNC("plus", a="one", b="two"), ", ", UTN("three"))), ("func(func1(one), two)", SCWC("func(", (")", 1), SCWC("func1(", ")", "one"), ", ", "two")) ]) def test_i_can_parse(self, text, expected): sheerka, context, parser = self.init_parser() resolved_expected = compute_expected_array(cmap, text, [expected])[0] res = parser.parse(context, ParserInput(text)) parser_result = res.body expression = res.body.body assert res.status assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT) assert expression == resolved_expected assert expression.python_node is not None assert expression.return_value is not None def test_i_can_parse_when_multiple_results_when_requested(self): sheerka, context, parser = self.init_parser() parser.longest_concepts_only = False text = "func(one, twenty two)" expected = [SCWC("func(", ")", "one", ", ", "twenty ", "two"), SCWC("func(", ")", "one", ", ", CN("twenties", source="twenty two"))] all_resolved_expected = compute_expected_array(cmap, text, expected) results = parser.parse(context, ParserInput(text)) assert len(results) == 2 for res, resolved_expected in zip(results, all_resolved_expected): parser_result = res.body expressions = res.body.body assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT) assert expressions == resolved_expected @pytest.mark.parametrize("text, expected_error_type", [ ("one", BuiltinConcepts.NOT_FOR_ME), ("$*!", BuiltinConcepts.NOT_FOR_ME), ("func(", BuiltinConcepts.ERROR), ("func(one", BuiltinConcepts.ERROR), ("func(one, two, ", BuiltinConcepts.ERROR), ("func(one) and func(two)", BuiltinConcepts.ERROR), ("one func(one)", BuiltinConcepts.NOT_FOR_ME), ]) def test_i_cannot_parse(self, text, expected_error_type): sheerka, context, parser = self.init_parser() res = parser.parse(context, ParserInput(text)) assert not res.status assert sheerka.isinstance(res.body, expected_error_type) @pytest.mark.parametrize("text, expected", [ ("func(one two)", SCWC("func(", ")", "one", "two")), ]) def test_i_can_detect_non_function(self, text, expected): sheerka, context, parser = self.init_parser() resolved_expected = compute_expected_array(cmap, text, [expected])[0] res = parser.parse(context, ParserInput(text)) parser_result = res.body expression = res.body.body assert not res.status assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT) assert expression == resolved_expected assert expression.python_node is None assert expression.return_value is None @pytest.mark.parametrize("sequence, expected", [ (None, None), ([["a"]], [["a"]]), ([["a"], ["b", "c"]], [["a"]]), ([["b", "c"], ["a"]], [["a"]]), ([["b", "c"], ["a"], ["d", "e"], ["f"]], [["a"], ["f"]]), ]) def test_i_can_get_the_longest_concept_sequence(self, sequence, expected): assert FunctionParser.get_longest_concepts(sequence) == expected def test_concepts_found_are_fully_initialized(self): sheerka, context, parser = self.init_parser() res = parser.parse(context, ParserInput("func(one plus three)")) concept = res.body.body.nodes[0].concept assert res.status assert isinstance(concept.compiled["a"], Concept) # three is not recognized, # so it will be transformed into list of ReturnValueConcept that indicate how to recognized it assert isinstance(concept.compiled["b"], list) for item in concept.compiled["b"]: assert sheerka.isinstance(item, BuiltinConcepts.RETURN_VALUE)