import asyncio import sys import pytest from rich.text import Text from falyx import Falyx from falyx.console import console as falyx_console from falyx.exceptions import FalyxError from falyx.parser import ParseResult from falyx.signals import BackSignal, CancelSignal, FlowSignal, HelpSignal, QuitSignal async def throw_error_action(error: str): if error == "QuitSignal": raise QuitSignal("Quit signal triggered.") elif error == "BackSignal": raise BackSignal("Back signal triggered.") elif error == "CancelSignal": raise CancelSignal("Cancel signal triggered.") elif error == "ValueError": raise ValueError("This is a ValueError.") elif error == "HelpSignal": raise HelpSignal("Help signal triggered.") elif error == "FalyxError": raise FalyxError("This is a FalyxError.") elif error == "FlowSignal": raise FlowSignal("Flow signal triggered.") else: raise asyncio.CancelledError("An error occurred in the action.") @pytest.fixture def flx() -> Falyx: sys.argv = ["falyx", "T"] flx = Falyx() flx.add_command( "T", "Test", action=lambda: "hello", ) flx.add_tldr_example( entry_key="T", usage="", description="This is a TLDR example for the T command.", ) return flx @pytest.fixture def flx_with_submenu() -> Falyx: flx = Falyx() submenu = Falyx("Submenu") submenu.add_command( "T", "Test", action=lambda: "hello from submenu", ) submenu.add_tldr_example( entry_key="T", usage="", description="This is a TLDR example for the T command in the submenu.", ) flx.add_submenu( "S", "Submenu", submenu=submenu, ) return flx @pytest.mark.asyncio async def test_run_basic(capsys): sys.argv = ["falyx", "-h"] flx = Falyx() with pytest.raises(SystemExit): await flx.run() captured = capsys.readouterr() assert "Show this help menu." in captured.out @pytest.mark.asyncio async def test_run_default_to_menu(flx): sys.argv = ["falyx", "T"] flx.default_to_menu = False with pytest.raises(SystemExit): await flx.run() await flx.run(always_start_menu=True) @pytest.mark.asyncio async def test_run_default_to_menu_help(flx): sys.argv = ["falyx"] flx.default_to_menu = False with pytest.raises(SystemExit, match="0"): with falyx_console.capture() as capture: await flx.run() captured = Text.from_ansi(capture.get()).plain assert "Show this help menu." in captured @pytest.mark.asyncio async def test_run_debug_hooks(flx): sys.argv = ["falyx", "--debug-hooks", "T"] assert flx.options.get("debug_hooks") is False with pytest.raises(SystemExit): await flx.run() assert flx.options.get("debug_hooks") is True @pytest.mark.asyncio async def test_run_never_prompt(flx): sys.argv = ["falyx", "--never-prompt", "T"] assert flx.options.get("never_prompt") is False with pytest.raises(SystemExit): await flx.run() falyx_console.print(flx.options.get_namespace_dict("default")) assert flx.options.get("debug_hooks") is False assert flx.options.get("never_prompt") is True @pytest.mark.asyncio async def test_run_bad_args(flx): sys.argv = ["falyx", "T", "--unknown-arg"] with pytest.raises(SystemExit, match="2"): await flx.run() @pytest.mark.asyncio async def test_run_help(flx): sys.argv = ["falyx", "T", "--help"] with pytest.raises(SystemExit, match="0"): await flx.run() sys.argv = ["falyx", "--help"] with pytest.raises(SystemExit, match="0"): await flx.run() sys.argv = ["falyx", "-h"] with pytest.raises(SystemExit, match="0"): await flx.run() sys.argv = ["falyx", "--tldr"] with pytest.raises(SystemExit, match="0"): await flx.run() sys.argv = ["falyx", "-T"] with pytest.raises(SystemExit, match="0"): await flx.run() @pytest.mark.asyncio async def test_run_entry_not_found(flx): sys.argv = ["falyx", "UNKNOWN_COMMAND"] with pytest.raises(SystemExit, match="2"): await flx.run() @pytest.mark.asyncio async def test_run_test_exceptions(flx): flx.add_command( "E", "Throw Error", action=throw_error_action, ) sys.argv = ["falyx", "E", "ValueError"] with pytest.raises(SystemExit, match="1"): await flx.run() sys.argv = ["falyx", "E", "QuitSignal"] with pytest.raises(SystemExit, match="130"): await flx.run() sys.argv = ["falyx", "E", "BackSignal"] with pytest.raises(SystemExit, match="1"): await flx.run() sys.argv = ["falyx", "E", "CancelSignal"] with pytest.raises(SystemExit, match="1"): await flx.run() sys.argv = ["falyx", "E", "HelpSignal"] with pytest.raises(SystemExit, match="1"): await flx.run() sys.argv = ["falyx", "E", "FlowSignal"] with pytest.raises(SystemExit, match="1"): await flx.run() sys.argv = ["falyx", "--verbose", "E", "FalyxError"] with pytest.raises(SystemExit, match="1"): await flx.run() sys.argv = ["falyx", "E", "UnknownError"] with pytest.raises(SystemExit, match="1"): await flx.run() @pytest.mark.asyncio async def test_run_no_args(flx): sys.argv = ["falyx"] with pytest.raises(SystemExit, match="0"): await flx.run() @pytest.mark.asyncio async def test_run_submenu(flx_with_submenu): sys.argv = ["falyx", "S", "T"] with pytest.raises(SystemExit, match="0"): await flx_with_submenu.run() @pytest.mark.asyncio async def test_run_submenu_help(flx_with_submenu): sys.argv = ["falyx", "S", "--help"] with pytest.raises(SystemExit, match="0"): await flx_with_submenu.run() @pytest.mark.asyncio async def test_run_submenu_tldr(flx_with_submenu): sys.argv = ["falyx", "S", "--tldr"] with pytest.raises(SystemExit, match="0"): await flx_with_submenu.run() @pytest.mark.asyncio async def test_run_preview(flx): sys.argv = ["falyx", "preview", "T"] with pytest.raises(SystemExit, match="0"): with falyx_console.capture() as capture: await flx.run() captured = Text.from_ansi(capture.get()).plain assert "Command: 'T'" in captured assert "Would call: (args=(), kwargs={})" in captured