Files
falyx/tests/test_falyx/test_execute_command.py
Roland Thomas efe3f5fd99 feat(core): clone commands and actions when binding runtimes
Add clone support across Action types and Command so commands can be safely
registered or runner-bound without mutating the original instances.

- clone BaseAction implementations across simple, composite, IO, prompt, file,
  HTTP, process, and signal actions
- bind cloned commands in Falyx.add_command_from_command() and CommandRunner
- preserve local never_prompt settings when cloning actions
- rename shared runtime state from options to options_manager for consistency
- seed root and execution option namespaces consistently
- apply scoped root and namespace option overrides during routing and dispatch
- improve namespace completion by delegating option suggestions to FalyxParser
- enrich missing-value errors and error hints
2026-06-07 13:04:35 -04:00

125 lines
3.3 KiB
Python

import pytest
from falyx import Falyx
from falyx.action import Action
from falyx.command_runner import CommandRunner
from falyx.parser import CommandArgumentParser
@pytest.mark.asyncio
async def test_execute_command():
"""Test if Falyx can run in run key mode."""
falyx = Falyx("Run Key Test")
falyx.add_command(
key="T",
description="Test Command",
action=lambda: "Hello, World!",
)
result = await falyx.execute_command("T")
assert result == "Hello, World!"
@pytest.mark.asyncio
async def test_execute_command_accepts_alias():
"""Falyx.execute_command should resolve command aliases."""
falyx = Falyx("Alias Test")
falyx.add_command(
key="T",
description="Test Command",
action=lambda: "Hello, Alias!",
aliases=["test"],
)
result = await falyx.execute_command("test")
assert result == "Hello, Alias!"
@pytest.mark.asyncio
async def test_execute_command_recover():
"""Test if Falyx can recover from a failure in run key mode."""
falyx = Falyx("Run Key Recovery Test")
state = {"count": 0}
async def flaky():
if not state["count"]:
state["count"] += 1
raise RuntimeError("Random failure!")
return "ok"
falyx.add_command(
key="E",
description="Error Command",
action=Action("flaky", flaky),
retry=True,
)
result = await falyx.execute_command("E")
assert result == "ok"
@pytest.mark.asyncio
async def test_execute_command_with_argument_parsing():
"""Falyx.execute_command should parse command-local arguments before execution."""
falyx = Falyx("Argument Parsing Test")
falyx.add_command(
key="G",
description="Greet",
action=lambda name: f"hello {name}",
)
result = await falyx.execute_command("G Roland")
assert result == "hello Roland"
@pytest.mark.asyncio
async def test_command_runner_and_falyx_execute_same_command_with_same_result():
"""CommandRunner and Falyx should produce the same result for equivalent input."""
falyx = Falyx("Parity Test")
command = falyx.add_command(
key="G",
description="Greet",
action=lambda name: f"hello {name}",
aliases=["greet"],
)
runner = CommandRunner.from_command(command)
falyx_result = await falyx.execute_command("G Roland")
runner_result = await runner.run(["Roland"])
assert falyx_result == "hello Roland"
assert runner_result == "hello Roland"
assert falyx_result == runner_result
@pytest.mark.asyncio
async def test_command_runner_from_command_clones_and_preserves_parity():
"""Runner parity should hold even though from_command binds a clone."""
falyx = Falyx("Clone Parity Test")
parser = CommandArgumentParser()
parser.add_argument("x", type=int)
parser.add_argument("y", type=int)
command = falyx.add_command(
key="A",
description="Add",
action=lambda x, y: x + y,
arg_parser=parser,
)
runner = CommandRunner.from_command(command)
result_from_falyx = await falyx.execute_command("A 2 3")
result_from_runner = await runner.run(["2", "3"])
assert result_from_falyx == 5
assert result_from_runner == 5
assert runner.command is not command