import pytest from core.builtin_concepts import BuiltinConcepts from parsers.BaseParser import UnexpectedTokenErrorNode, UnexpectedEof from parsers.ExplainParser import ExplainParser, ExplanationNode, MultipleDigestError, ValueErrorNode, \ RecurseDefNode, FormatLNode, UnionNode, FilterNode, FormatDNode from parsers.ExpressionParser import PropertyContainsNode, PropertyEqualsNode, TrueNode, AndNode, OrNode from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka class TestExplainParser(TestUsingMemoryBasedSheerka): def init_parser(self, **kwargs): sheerka = self.get_sheerka(singleton=True, **kwargs) context = self.get_context(sheerka) parser = ExplainParser() return sheerka, context, parser def test_i_cannot_parse_empty_string(self): sheerka, context, parser = self.init_parser() res = parser.parse(context, "") assert not res.status assert sheerka.isinstance(res.body, BuiltinConcepts.NOT_FOR_ME) def test_i_cannot_parse_if_not_for_me(self): sheerka, context, parser = self.init_parser() text = "foo" res = parser.parse(context, text) not_for_me = res.body assert not res.status assert sheerka.isinstance(not_for_me, BuiltinConcepts.NOT_FOR_ME) assert not_for_me.body == text assert isinstance(not_for_me.reason[0], UnexpectedTokenErrorNode) @pytest.mark.parametrize("text, digest, command, directives", [ # ("explain", "", "explain", []), ("explain digest", "digest", "explain digest", []), ("explain -r 3", "", "explain -r 3", [RecurseDefNode(3)]), ("explain digest -r 3", "digest", "explain digest -r 3", [RecurseDefNode(3)]), ]) def test_i_can_parse_explain_without_filter(self, text, digest, command, directives): sheerka, context, parser = self.init_parser() res = parser.parse(context, text) parser_result = res.body explanation_node = res.body.body assert res.status assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT) assert parser_result.parser.name == "parsers.Explain" assert parser_result.source == text assert explanation_node.digest == digest assert explanation_node.command == command assert explanation_node.expr == UnionNode([FilterNode(TrueNode(), directives)]) def test_i_can_parse_using_filter(self): sheerka, context, parser = self.init_parser() text = "explain -f a=b" res = parser.parse(context, text) parser_result = res.body explanation_node = res.body.body assert res.status assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT) assert parser_result.parser.name == "parsers.Explain" assert parser_result.source == text assert explanation_node.expr == UnionNode([ FilterNode(TrueNode()), FilterNode(PropertyContainsNode("a", "b"))]) @pytest.mark.parametrize("text, expected", [ ("-f a==b", PropertyEqualsNode("a", "b")), ("--filter a==b", PropertyEqualsNode("a", "b")), ("-f a==b and c=d", AndNode(PropertyEqualsNode("a", "b"), PropertyContainsNode("c", "d"))), ("-f a==b or c=d", OrNode(PropertyEqualsNode("a", "b"), PropertyContainsNode("c", "d"))), ("-f a==b or c==d and e==f", OrNode( PropertyEqualsNode("a", "b"), AndNode(PropertyEqualsNode("c", "d"), PropertyEqualsNode("e", "f")))), ("-f a==b and c==d or e==f", OrNode( AndNode(PropertyEqualsNode("a", "b"), PropertyEqualsNode("c", "d")), PropertyEqualsNode("e", "f"))), ("-f (a==b or c==d) and e==f", AndNode( OrNode(PropertyEqualsNode("a", "b"), PropertyEqualsNode("c", "d")), PropertyEqualsNode("e", "f"))), ]) def test_i_can_parse_filter_expressions(self, text, expected): sheerka, context, parser = self.init_parser() res = parser.parse(context, "explain " + text) parser_result = res.body explanation_node = res.body.body expr_node = explanation_node.expr.filters[-1].expr assert res.status assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT) assert isinstance(explanation_node, ExplanationNode) assert expr_node == expected @pytest.mark.parametrize("text, expected", [ ("-r 2", [ FilterNode(TrueNode(), [RecurseDefNode(2)]) ]), ("--format_l 'abc'", [ FilterNode(TrueNode(), [FormatLNode('abc')]) ]), ("--format_d 'abc'", [ FilterNode(TrueNode(), [FormatDNode({"abc": "{abc}"})]) ]), ("--format_d a,b,c", [ FilterNode(TrueNode(), [FormatDNode({"a": "{a}", "b": "{b}", "c": "{c}"})]) ]), ("--format_d a , b , c", [ FilterNode(TrueNode(), [FormatDNode({"a": "{a}", "b": "{b}", "c": "{c}"})]) ]), ("-r 2 --format_l 'abc'", [ FilterNode(TrueNode(), [RecurseDefNode(2), FormatLNode('abc')]) ]), ("--format_d a, b -r 2", [ FilterNode(TrueNode(), [FormatDNode({"a": "{a}", "b": "{b}"}), RecurseDefNode(2)]) ]), ("-f a==b -r 3", [ FilterNode(TrueNode()), FilterNode(PropertyEqualsNode("a", "b"), [RecurseDefNode(3)]), ]), ("-f a==b --format_l 'abc'", [ FilterNode(TrueNode()), FilterNode(PropertyEqualsNode("a", "b"), [FormatLNode("abc")]), ]), ("-r 3 -f a==b", [ FilterNode(TrueNode(), [RecurseDefNode(3)]), FilterNode(PropertyEqualsNode("a", "b"), []), ]), ("--format_l 'abc' -f a==b", [ FilterNode(TrueNode(), [FormatLNode("abc")]), FilterNode(PropertyEqualsNode("a", "b"), []), ]), ("-f a==b -f c==d", [ FilterNode(TrueNode()), FilterNode(PropertyEqualsNode("a", "b")), FilterNode(PropertyEqualsNode("c", "d")) ]), ("-r 1 -f a==b -r 2 -f c==d -r 3", [ FilterNode(TrueNode(), [RecurseDefNode(1)]), FilterNode(PropertyEqualsNode("a", "b"), [RecurseDefNode(2)]), FilterNode(PropertyEqualsNode("c", "d"), [RecurseDefNode(3)]) ]), ]) def test_i_can_parse_other_directives(self, text, expected): sheerka, context, parser = self.init_parser() res = parser.parse(context, "explain " + text) parser_result = res.body explanation_node = res.body.body expr_node = explanation_node.expr assert res.status assert sheerka.isinstance(parser_result, BuiltinConcepts.PARSER_RESULT) assert isinstance(explanation_node, ExplanationNode) assert expr_node.filters == expected @pytest.mark.parametrize("text, expected", [ ("explain -d digest", "digest"), ("explain -d", ""), ("explain -d -f a=b", "") ]) def test_i_can_parse_record_digest(self, text, expected): sheerka, context, parser = self.init_parser() res = parser.parse(context, text) explanation_node = res.body.body assert explanation_node.digest == expected assert explanation_node.record_digest @pytest.mark.parametrize("text, expected_error_type", [ ("explain digest1 digest2", MultipleDigestError), ("explain -r", UnexpectedEof), ("explain -r foo", ValueErrorNode), ("explain -r 1.2", ValueErrorNode), ("explain -f -r 1.2", UnexpectedTokenErrorNode), ("explain -f", UnexpectedEof), ("explain --format_d", UnexpectedEof), ("explain --format_l", UnexpectedEof), ("explain --format_l -r foo", UnexpectedTokenErrorNode), ("explain --format_d -r foo", UnexpectedTokenErrorNode), ]) def test_i_cannot_parse(self, text, expected_error_type): sheerka, context, parser = self.init_parser() res = parser.parse(context, text) error = res.body errors = res.body.body assert not res.status assert sheerka.isinstance(error, BuiltinConcepts.ERROR) assert len(errors) == 1 assert isinstance(errors[0], expected_error_type)