from parsimonious.grammar import Grammar from customcmd.parser import Execuitor, ExecContext from customcmd.client import ExecClient import pytest import asyncio # from customcmd.parser.context import ExecScope @pytest.fixture def grammar(): with open("assets/grammar.ppeg") as f: return Grammar(f.read()) @pytest.fixture def executor(): return Execuitor() @pytest.fixture def context(): ctx = ExecContext( alias='test_cmd', args=["testarg1", "testarg2"], content="Base content" ) return ctx @pytest.fixture def client(): return ExecClient() class TestObject: _exec_attr_name = "testingobj" _exec_attr_number = 7 async def _exec_attr_functor(self, ctx, arg1): return f"Rec {arg1}" async def _exec_attr_functown(self, ctx, arg1): return TestObject() def __call__(self, ctx, arg1): return self.dummy_call(ctx, arg1) async def dummy_call(self, ctx, arg1): return TestObject() def __str__(self): return "Testing Object" class TestGrammar: async def run_command(self, grammar, executor, context, command): tree = grammar.parse(command) lazyterm = executor.visit(tree) return await lazyterm.execute(context) @pytest.mark.asyncio async def test_literals(self, grammar, executor, context): expected_results = [ ('${""}', ""), ('${"abc"}', "abc"), ('${ "abc" }', "abc"), ("${1}", "1"), ("${True}", "True"), ("${False}", "False"), ] for command, expected in expected_results: actual = await self.run_command(grammar, executor, context, command) assert actual == expected @pytest.mark.asyncio async def test_ternary(self, grammar, executor, context): expected_results = [ ('${"a"?"b":"c"}', "b"), ('${""?"b":"c"}', "c"), ('${ "a" ? "b" : "c" }', "b"), ('${ 1 ? "b" : "c" }', "b"), ('${ 0 ? "b" : "c" }', "c"), ] for command, expected in expected_results: actual = await self.run_command(grammar, executor, context, command) assert actual == expected @pytest.mark.asyncio async def test_cmdarg(self, grammar, executor, context): expected_results = [ ("${$0}", "test_cmd"), ("${$1}", "testarg1"), ("${$1*}", "testarg1 testarg2"), ("${$3}", ""), ("${ $2 }", "testarg2"), ] for command, expected in expected_results: actual = await self.run_command(grammar, executor, context, command) assert actual == expected @pytest.mark.asyncio async def test_cascade(self, grammar, executor, context): expected_results = [ ('${""|"result"}', "result"), ('${"first"|"result"}', "first"), ('${"first"|"second"|"result"}', "first"), ('${""|"second"|"result"}', "second"), ('${""|""|"result"}', "result"), ('${""|0|"result"}', "result"), ('${0|1|"result"}', "1"), ] for command, expected in expected_results: actual = await self.run_command(grammar, executor, context, command) assert actual == expected @pytest.mark.asyncio async def test_define_equals(self, grammar, executor, context): expected_results = [ ("${a}", "a"), ("${(b = 1) | b}", "1"), ("${(d = 1) | (c = d) | c}", "1"), ("${(e = f) | (f = 1) | e}", "f"), ] for command, expected in expected_results: actual = await self.run_command(grammar, executor, context, command) assert actual == expected @pytest.mark.asyncio async def test_define_walrus(self, grammar, executor, context): expected_results = [ ("${a}", "a"), ("${b := 1}", "1"), ] for command, expected in expected_results: actual = await self.run_command(grammar, executor, context, command) assert actual == expected @pytest.mark.asyncio async def test_define_term(self, grammar, executor, context): expected_results = [ ("${a}", "a"), ("${(b ::= 1) | b}", "1"), ("${(d ::= 1) | (c ::= d) | c}", "1"), ("${(e ::= f) | (f ::= 1) | e}", "1"), ] for command, expected in expected_results: actual = await self.run_command(grammar, executor, context, command) assert actual == expected @pytest.mark.asyncio async def test_basic_obj(self, grammar, executor, context): context.this_scope["obj"] = TestObject() expected_results = [ ("${obj}", "Testing Object"), ("${obj.name}", "testingobj"), ("${obj.number}", "7"), ('${obj.functor "abc"}', "Rec abc"), ("${(obj.functown abc).functor abc}", "Rec abc"), ("${(obj abc).functor abc}", "Rec abc"), ] for command, expected in expected_results: actual = await self.run_command(grammar, executor, context, command) assert actual == expected @pytest.mark.asyncio async def test_compare(self, grammar, executor, context): expected_results = [ ("${1 == 1}", "True"), ("${1 != 2}", "True"), ("${1 <= 2}", "True"), ("${1 <= 1}", "True"), ("${1 < 2}", "True"), ("${1 > 2}", "False"), ("${1 >= 2}", "False"), ("${1 == 2}", "False"), ('${(1 == 2)?"a":"b"}', "b"), ('${(1 == 1)?"a":"b"}', "a"), ] for command, expected in expected_results: actual = await self.run_command(grammar, executor, context, command) assert actual == expected @pytest.mark.asyncio async def test_ops(self, grammar, executor, context): expected_results = [ ("${1 + 1}", "2"), ("${1 + 2 + 3}", "6"), ("${1 - 1}", "0"), ("${4 / 2}", "2.0"), ("${5 % 2}", "1"), ("${5 * 2}", "10"), ("${5 * 2 * 3}", "30"), ("${5 // 2}", "2"), ("${2 ** 3}", "8"), ("${2 ** 3}", "8"), ("${True && False}", "False"), ("${True || False}", "True"), ("${True && True}", "True"), ("${False || False}", "False"), ('${"abc" + "def"}', "abcdef"), ] for command, expected in expected_results: actual = await self.run_command(grammar, executor, context, command) assert actual == expected @pytest.mark.asyncio async def test_compound(self, grammar, executor, context): expected_results = [ ('${(a = 1) | (b = 1) | ((a == b)? 1 :"Failed")}', "1"), ] for command, expected in expected_results: actual = await self.run_command(grammar, executor, context, command) assert actual == expected class TestClient: @pytest.mark.asyncio async def test_command_1(self, client, context): actual = await client.run_command( context, '${(a = 1) | (b = 1) | ((a == b)? 1 :"Failed")}' ) assert actual == "1" @pytest.mark.asyncio async def test_command_2(self, client, context): actual = await client.run_command(context, "A test ${2} of the client ${$2}") assert actual == "A test 2 of the client testarg2" class LaterTestScope: def test_scope_toplevel(self): scope = ExecScope() scope['key'] = 'value' assert scope['key'] == 'value' def test_scope_stack(self): scope = ExecScope() scope['key'] = 'value1' scope.enter_scope() assert scope['key'] == 'value1' scope['key'] = 'value12' assert scope['key'] == 'value12' scope['key2'] = 'value2' assert scope['key2'] == 'value2' scope.leave_scope() assert scope.get('key2') is None assert scope['key'] == 'value' def test_scope_enter_init(self): scope = ExecScope(key="value1") assert scope['key'] == 'value1' scope.enter_scope(key2="value2") assert scope['key2'] == 'value2' scope.leave_scope() assert scope.get('key2') is None assert scope.get('key') == 'value1'