import pytest from core.sheerka.services.SheerkaExecute import ParserInput from parsers.ArithmericOperatorParser import ArithmeticOperatorParser from parsers.BaseExpressionParser import LeftPartNotFoundError, ParenthesisMismatchError, RightPartNotFoundError from parsers.BaseParser import ErrorSink from parsers.ExpressionParser import ExpressionParser from parsers.FunctionParser import FunctionParser from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka from tests.parsers.parsers_utils import ADD, DIV, EXPR, FDIV, FN, LT, MOD, MULT, POW, SEQ, SUB, VAR, \ get_expr_node_from_test_node class TestArithmeticOperatorParser(TestUsingMemoryBasedSheerka): def init_parser(self, expr_parser=None, function_parser=None): sheerka, context = self.init_concepts() expr_parser = expr_parser or ExpressionParser(auto_compile=False) parser = ArithmeticOperatorParser(expr_parser=expr_parser, function_parser=function_parser) return sheerka, context, parser @pytest.mark.parametrize("expression, expected", [ ("one complicated expression", VAR("one complicated expression")), ("a + b", ADD(VAR("a"), VAR("b"))), ("a - b", SUB("a", "b")), ("a * b", MULT("a", "b")), ("a / b", DIV("a", "b")), ("a // b", FDIV("a", "b")), ("a % b", MOD("a", "b")), ("a ** b", POW("a", "b")), ("a + b * c", ADD("a", MULT("b", "c"))), ("a * b + c", ADD(MULT("a", "b"), "c")), ("a * b ** c", MULT("a", POW("b", "c"))), ("a ** b * c", MULT(POW("a", "b"), "c")), ("(a + b) * c", MULT(ADD("a", "b"), "c", source="(a + b) * c")), ("a * (b + c)", MULT("a", ADD("b", "c"), source="a * (b + c)")), ("func(a, b) * 3", MULT(FN(EXPR("func"), EXPR("a"), EXPR("b")), EXPR("3"))), ("3 * func(a, b)", MULT(EXPR("3"), FN(EXPR("func"), EXPR("a"), EXPR("b")))), ("a + b + c", ADD("a", "b", "c")), ("a - b - c", SUB("a", "b", "c")), ("a + b - c - d", SUB(ADD("a", "b"), "c", "d")), ("a * b * c + d + e + f", ADD(MULT("a", "b", "c"), "d", "e", "f")), ("a + b < c", ADD("a", LT("b", "c"))), # this is possible is function_parser is not set ("foo x + y", SEQ(EXPR("foo "), ADD("x", "y"))), # to manager concept call ("long name concept x + y + z", SEQ(EXPR("long name concept "), ADD("x", "y", "z"))), ("long name concept x + y - z", SEQ(EXPR("long name concept "), SUB(ADD("x", "y"), "z"))), ("long name concept x + y * z", SEQ(EXPR("long name concept "), ADD("x", MULT("y", "z")))), ("long name concept x * y + z", SEQ(EXPR("long name concept "), ADD(MULT("x", "y"), "z"))), ("(foo x) + y", ADD("foo x", "y", source="(foo x) + y")), ("a + foo x + y", ADD("a", SEQ(EXPR("foo "), ADD("x", "y")))), ("a + b * foo x * y + z", ADD("a", MULT("b", SEQ(EXPR("foo "), ADD(MULT("x", "y"), "z"))))), ("a + foo b + c + bar e + f", ADD("a", SEQ(EXPR("foo "), ADD("b", "c", SEQ(EXPR("bar "), ADD("e", "f")))))), ("a + foo x", ADD("a", "foo x")), ("a + x y bar + b - c", ADD("a", SEQ(EXPR("x y "), SUB(ADD("bar", "b"), "c")))), ("a + x + y bar + b - c", ADD("a", "x", SEQ(EXPR("y "), SUB(ADD("bar", "b"), "c")))), ("a + x ? y : z + b - c", ADD("a", SEQ(EXPR("x ? y : "), SUB(ADD("z", "b"), "c")))), ("twenty one + 3", SEQ(EXPR("twenty "), ADD("one", EXPR("3")))), ("(foo x) * (bar y)", MULT("foo x", "bar y", source="(foo x) * (bar y)")) ]) def test_i_can_parse_input_expression(self, expression, expected): sheerka, context, parser = self.init_parser() parser_input = ParserInput(expression).reset() parser_input.next_token() error_sink = ErrorSink() expr = parser.parse_input(context, parser_input, error_sink) assert not error_sink.has_error expected = get_expr_node_from_test_node(expression, expected, default_expr_obj=VAR) assert expr == expected @pytest.mark.parametrize("expression, expected", [ ("one complicated expression", VAR("one complicated expression")), ("a + b", ADD(VAR("a"), VAR("b"))), ("func(a, b) * 3", MULT(FN(EXPR("func"), EXPR("a"), EXPR("b")), EXPR("3"))), ("3 * func(a, b)", MULT(EXPR("3"), FN(EXPR("func"), EXPR("a"), EXPR("b")))), ("a + b < c", ADD("a", EXPR("b < c"))), # the comparison is no longer recognized ("foo x + y", SEQ(EXPR("foo "), ADD("x", "y"))), # to manager concept call ("long name concept x + y + z", SEQ(EXPR("long name concept "), ADD("x", "y", "z"))), ("long name concept x + y - z", SEQ(EXPR("long name concept "), SUB(ADD("x", "y"), "z"))), ("long name concept x + y * z", SEQ(EXPR("long name concept "), ADD("x", MULT("y", "z")))), ("long name concept x * y + z", SEQ(EXPR("long name concept "), ADD(MULT("x", "y"), "z"))), ("(foo x) + y", ADD("foo x", "y", source="(foo x) + y")), ("a + foo x + y", ADD("a", SEQ(EXPR("foo "), ADD("x", "y")))), ("a + b * foo x * y + z", ADD("a", MULT("b", SEQ(EXPR("foo "), ADD(MULT("x", "y"), "z"))))), ("a + foo b + c + bar e + f", ADD("a", SEQ(EXPR("foo "), ADD("b", "c", SEQ(EXPR("bar "), ADD("e", "f")))))), ("a + foo x", ADD("a", "foo x")), ("a + x y bar + b - c", ADD("a", SEQ(EXPR("x y "), SUB(ADD("bar", "b"), "c")))), ("a + x + y bar + b - c", ADD("a", "x", SEQ(EXPR("y "), SUB(ADD("bar", "b"), "c")))), ("a + x ? y : z + b - c", ADD("a", SEQ(EXPR("x ? y : "), SUB(ADD("z", "b"), "c")))), ("(foo x) * (bar y) + 2", ADD(MULT("foo x", "bar y", source="(foo x) * (bar y)"), EXPR("2"))), ]) def test_i_can_parse_input_when_function_parser_is_set(self, expression, expected): sheerka, context, parser = self.init_parser(function_parser=FunctionParser()) parser_input = ParserInput(expression).reset() parser_input.next_token() error_sink = ErrorSink() expr = parser.parse_input(context, parser_input, error_sink) assert not error_sink.has_error expected = get_expr_node_from_test_node(expression, expected, default_expr_obj=VAR) assert expr == expected @pytest.mark.parametrize("expression, expected_error, expr_is_none", [ ("a +", [RightPartNotFoundError], False), ("+ a", [LeftPartNotFoundError], True), ("a ++ b", [RightPartNotFoundError], False), ("(a + b", [ParenthesisMismatchError], False), # ("a + b)", [ParenthesisMismatchError], False), # only detected is strict is on ]) def test_i_can_detect_errors(self, expression, expected_error, expr_is_none): sheerka, context, parser = self.init_parser() parser_input = ParserInput(expression).reset() parser_input.next_token() error_sink = ErrorSink() expr = parser.parse_input(context, parser_input, error_sink) assert error_sink.has_error assert (expr is None) == expr_is_none resolved_errors = [type(e) for e in error_sink.sink] assert resolved_errors == expected_error