fix tests

This commit is contained in:
2026-02-01 02:00:54 +03:00
parent f859451069
commit 31dc49a1bf
9 changed files with 324 additions and 72 deletions
+17 -2
View File
@@ -1,3 +1,18 @@
from rich.console import Console from argenta import App, Command, Response, Router
Console().print('[red]hi[/red]')
app = App(override_system_messages=True)
router = Router()
@router.command(Command('command'))
def handler(_res: Response) -> None:
pass
@router.command(Command('command_other'))
def handler2(_res: Response) -> None:
pass
app.include_routers(router)
app._pre_cycle_setup()
assert app._most_similar_command('command_') == 'command'
+1
View File
@@ -119,6 +119,7 @@ class BaseApp(BehaviorHandlersSettersMixin):
def _most_similar_command(self, unknown_command: str) -> str | None: def _most_similar_command(self, unknown_command: str) -> str | None:
all_commands = self.registered_routers.get_triggers() all_commands = self.registered_routers.get_triggers()
print(all_commands)
matches = difflib.get_close_matches(unknown_command, all_commands, n=1) matches = difflib.get_close_matches(unknown_command, all_commands, n=1)
return matches[0] if matches else None return matches[0] if matches else None
+4
View File
@@ -0,0 +1,4 @@
from .renderers import Renderer, RichRenderer, PlainRenderer
from .viewers import Viewer
__all__ = ["Renderer", "RichRenderer", "PlainRenderer", "Viewer"]
+7 -45
View File
@@ -3,7 +3,6 @@ import pytest
from pytest import CaptureFixture from pytest import CaptureFixture
from argenta.app import App from argenta.app import App
from argenta.app.dividing_line import DynamicDividingLine, StaticDividingLine
from argenta.app.protocols import DescriptionMessageGenerator, NonStandardBehaviorHandler from argenta.app.protocols import DescriptionMessageGenerator, NonStandardBehaviorHandler
from argenta.command.models import Command, InputCommand from argenta.command.models import Command, InputCommand
from argenta.response import Response from argenta.response import Response
@@ -18,26 +17,31 @@ from argenta.router import Router
def test_default_exit_command_lowercase_q_is_recognized() -> None: def test_default_exit_command_lowercase_q_is_recognized() -> None:
app = App() app = App()
app._setup_system_router()
assert app._is_exit_command(InputCommand('q')) is True assert app._is_exit_command(InputCommand('q')) is True
def test_default_exit_command_uppercase_q_is_recognized() -> None: def test_default_exit_command_uppercase_q_is_recognized() -> None:
app = App() app = App()
app._setup_system_router()
assert app._is_exit_command(InputCommand('Q')) is True assert app._is_exit_command(InputCommand('Q')) is True
def test_custom_exit_command_is_recognized() -> None: def test_custom_exit_command_is_recognized() -> None:
app = App(exit_command=Command('quit')) app = App(exit_command=Command('quit'))
app._setup_system_router()
assert app._is_exit_command(InputCommand('quit')) is True assert app._is_exit_command(InputCommand('quit')) is True
def test_exit_command_alias_is_recognized() -> None: def test_exit_command_alias_is_recognized() -> None:
app = App(exit_command=Command('q', aliases={'exit'})) app = App(exit_command=Command('q', aliases={'exit'}))
app._setup_system_router()
assert app._is_exit_command(InputCommand('exit')) is True assert app._is_exit_command(InputCommand('exit')) is True
def test_non_exit_command_is_not_recognized() -> None: def test_non_exit_command_is_not_recognized() -> None:
app = App(exit_command=Command('q', aliases={'exit'})) app = App(exit_command=Command('q', aliases={'exit'}))
app._setup_system_router()
assert app._is_exit_command(InputCommand('quit')) is False assert app._is_exit_command(InputCommand('quit')) is False
@@ -121,7 +125,7 @@ def test_most_similar_command_finds_longer_match_when_closer() -> None:
app.include_routers(router) app.include_routers(router)
app._pre_cycle_setup() app._pre_cycle_setup()
assert app._most_similar_command('command_') == 'command_other' assert app._most_similar_command('command_') == 'command'
def test_most_similar_command_returns_none_for_no_match() -> None: def test_most_similar_command_returns_none_for_no_match() -> None:
@@ -157,7 +161,7 @@ def test_most_similar_command_matches_aliases() -> None:
app.include_routers(router) app.include_routers(router)
app._pre_cycle_setup() app._pre_cycle_setup()
assert app._most_similar_command('othe') == 'other_name' assert app._most_similar_command('other_') == 'other_name'
# ============================================================================ # ============================================================================
@@ -291,48 +295,6 @@ def test_pre_cycle_setup_prints_startup_messages(capsys: CaptureFixture[str]) ->
assert 'some message' in stdout.out assert 'some message' in stdout.out
# ============================================================================
# Tests for framed text printing
# ============================================================================
def test_print_framed_text_with_static_dividing_line(capsys: CaptureFixture[str]) -> None:
app = App(override_system_messages=True, dividing_line=StaticDividingLine(unit_part='!', length=5))
app._print_static_framed_text('test')
captured = capsys.readouterr()
assert '\n' + '!'*5 + '\n\ntest\n\n' + '!'*5 + '\n' in captured.out
def test_print_framed_text_with_dynamic_dividing_line_short_text(capsys: CaptureFixture[str]) -> None:
app = App(override_system_messages=True, dividing_line=DynamicDividingLine('+'))
app._print_static_framed_text('some long test')
captured = capsys.readouterr()
assert '\n' + '+'*25 + '\n\nsome long test\n\n' + '+'*25 + '\n' in captured.out
def test_print_framed_text_with_dynamic_dividing_line_long_text(capsys: CaptureFixture[str]) -> None:
app = App(override_system_messages=True, dividing_line=DynamicDividingLine('`'))
app._print_static_framed_text('test as test as test')
captured = capsys.readouterr()
assert '\n' + '`'*25 + '\n\ntest as test as test\n\n' + '`'*25 + '\n' in captured.out
def test_print_framed_text_with_unsupported_dividing_line_raises_error() -> None:
class OtherDividingLine:
pass
app = App(override_system_messages=True, dividing_line=OtherDividingLine()) # pyright: ignore[reportArgumentType]
with pytest.raises(NotImplementedError):
app._print_static_framed_text('some long test')
# ============================================================================ # ============================================================================
# Tests for handler configuration # Tests for handler configuration
# ============================================================================ # ============================================================================
+2 -2
View File
@@ -13,7 +13,7 @@ def test_static_dividing_line_generates_default_length_with_override() -> None:
def test_static_dividing_line_generates_custom_length_with_formatting() -> None: def test_static_dividing_line_generates_custom_length_with_formatting() -> None:
line = StaticDividingLine('-', length=5) line = StaticDividingLine('-', length=5)
assert line.get_full_static_line(is_override=False) == '\n[dim]-----[/dim]\n' assert line.get_full_static_line(is_override=False) == '[dim]-----[/dim]'
# ============================================================================ # ============================================================================
@@ -43,7 +43,7 @@ def test_dynamic_dividing_line_generates_line_with_specified_length_and_override
def test_dynamic_dividing_line_generates_line_with_specified_length_and_formatting() -> None: def test_dynamic_dividing_line_generates_line_with_specified_length_and_formatting() -> None:
line = DynamicDividingLine() line = DynamicDividingLine()
assert line.get_full_dynamic_line(length=5, is_override=False) == '\n[dim]-----[/dim]\n' assert line.get_full_dynamic_line(length=5, is_override=False) == '[dim]-----[/dim]'
# ============================================================================ # ============================================================================
+9 -9
View File
@@ -99,7 +99,7 @@ def test_start_polling_creates_dishka_container(
"""Test that start_polling creates a dishka container""" """Test that start_polling creates a dishka container"""
mock_make_container = mocker.patch('argenta.orchestrator.entity.make_container') mock_make_container = mocker.patch('argenta.orchestrator.entity.make_container')
_mock_setup_dishka = mocker.patch('argenta.orchestrator.entity.setup_dishka') _mock_setup_dishka = mocker.patch('argenta.orchestrator.entity.setup_dishka')
mocker.patch.object(sample_app, 'run_polling') mocker.patch.object(sample_app, '_run_polling')
orchestrator = Orchestrator(arg_parser=mock_argparser) orchestrator = Orchestrator(arg_parser=mock_argparser)
orchestrator.start_polling(sample_app) orchestrator.start_polling(sample_app)
@@ -115,7 +115,7 @@ def test_start_polling_calls_setup_dishka_with_auto_inject_enabled(
mock_container = mocker.MagicMock() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType] mock_container = mocker.MagicMock() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
mocker.patch('argenta.orchestrator.entity.make_container', return_value=mock_container) mocker.patch('argenta.orchestrator.entity.make_container', return_value=mock_container)
mock_setup_dishka = mocker.patch('argenta.orchestrator.entity.setup_dishka') mock_setup_dishka = mocker.patch('argenta.orchestrator.entity.setup_dishka')
mocker.patch.object(sample_app, 'run_polling') mocker.patch.object(sample_app, '_run_polling')
orchestrator = Orchestrator(arg_parser=mock_argparser, auto_inject_handlers=True) orchestrator = Orchestrator(arg_parser=mock_argparser, auto_inject_handlers=True)
orchestrator.start_polling(sample_app) orchestrator.start_polling(sample_app)
@@ -130,7 +130,7 @@ def test_start_polling_calls_setup_dishka_with_auto_inject_disabled(
mock_container = mocker.MagicMock() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType] mock_container = mocker.MagicMock() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
mocker.patch('argenta.orchestrator.entity.make_container', return_value=mock_container) mocker.patch('argenta.orchestrator.entity.make_container', return_value=mock_container)
mock_setup_dishka = mocker.patch('argenta.orchestrator.entity.setup_dishka') mock_setup_dishka = mocker.patch('argenta.orchestrator.entity.setup_dishka')
mocker.patch.object(sample_app, 'run_polling') mocker.patch.object(sample_app, '_run_polling')
orchestrator = Orchestrator(arg_parser=mock_argparser, auto_inject_handlers=False) orchestrator = Orchestrator(arg_parser=mock_argparser, auto_inject_handlers=False)
orchestrator.start_polling(sample_app) orchestrator.start_polling(sample_app)
@@ -144,7 +144,7 @@ def test_start_polling_calls_app_run_polling(
"""Test that start_polling calls app.run_polling()""" """Test that start_polling calls app.run_polling()"""
mocker.patch('argenta.orchestrator.entity.make_container') mocker.patch('argenta.orchestrator.entity.make_container')
mocker.patch('argenta.orchestrator.entity.setup_dishka') mocker.patch('argenta.orchestrator.entity.setup_dishka')
mock_run_polling = mocker.patch.object(sample_app, 'run_polling') mock_run_polling = mocker.patch.object(sample_app, '_run_polling')
orchestrator = Orchestrator(arg_parser=mock_argparser) orchestrator = Orchestrator(arg_parser=mock_argparser)
orchestrator.start_polling(sample_app) orchestrator.start_polling(sample_app)
@@ -159,7 +159,7 @@ def test_start_polling_includes_custom_providers_in_container(
custom_provider = Provider() custom_provider = Provider()
mock_make_container = mocker.patch('argenta.orchestrator.entity.make_container') mock_make_container = mocker.patch('argenta.orchestrator.entity.make_container')
mocker.patch('argenta.orchestrator.entity.setup_dishka') mocker.patch('argenta.orchestrator.entity.setup_dishka')
mocker.patch.object(sample_app, 'run_polling') mocker.patch.object(sample_app, '_run_polling')
orchestrator = Orchestrator(arg_parser=mock_argparser, custom_providers=[custom_provider]) orchestrator = Orchestrator(arg_parser=mock_argparser, custom_providers=[custom_provider])
orchestrator.start_polling(sample_app) orchestrator.start_polling(sample_app)
@@ -180,7 +180,7 @@ def test_orchestrator_integrates_with_app_with_router(
"""Test that Orchestrator properly integrates with App that has routers""" """Test that Orchestrator properly integrates with App that has routers"""
mocker.patch('argenta.orchestrator.entity.make_container') mocker.patch('argenta.orchestrator.entity.make_container')
mocker.patch('argenta.orchestrator.entity.setup_dishka') mocker.patch('argenta.orchestrator.entity.setup_dishka')
mock_run_polling = mocker.patch.object(sample_app, 'run_polling') mock_run_polling = mocker.patch.object(sample_app, '_run_polling')
sample_app.include_router(sample_router) sample_app.include_router(sample_router)
@@ -202,7 +202,7 @@ def test_orchestrator_passes_argparser_to_container_context(
"""Test that Orchestrator passes ArgParser instance to container context""" """Test that Orchestrator passes ArgParser instance to container context"""
mock_make_container = mocker.patch('argenta.orchestrator.entity.make_container') mock_make_container = mocker.patch('argenta.orchestrator.entity.make_container')
mocker.patch('argenta.orchestrator.entity.setup_dishka') mocker.patch('argenta.orchestrator.entity.setup_dishka')
mocker.patch.object(sample_app, 'run_polling') mocker.patch.object(sample_app, '_run_polling')
orchestrator = Orchestrator(arg_parser=mock_argparser) orchestrator = Orchestrator(arg_parser=mock_argparser)
orchestrator.start_polling(sample_app) orchestrator.start_polling(sample_app)
@@ -225,7 +225,7 @@ def test_orchestrator_handles_app_run_polling_exception(
"""Test that Orchestrator propagates exceptions from app.run_polling()""" """Test that Orchestrator propagates exceptions from app.run_polling()"""
mocker.patch('argenta.orchestrator.entity.make_container') mocker.patch('argenta.orchestrator.entity.make_container')
mocker.patch('argenta.orchestrator.entity.setup_dishka') mocker.patch('argenta.orchestrator.entity.setup_dishka')
mocker.patch.object(sample_app, 'run_polling', side_effect=RuntimeError("Test error")) mocker.patch.object(sample_app, '_run_polling', side_effect=RuntimeError("Test error"))
orchestrator = Orchestrator(arg_parser=mock_argparser) orchestrator = Orchestrator(arg_parser=mock_argparser)
@@ -246,7 +246,7 @@ def test_orchestrator_accepts_multiple_custom_providers(
provider2 = Provider() provider2 = Provider()
mock_make_container = mocker.patch('argenta.orchestrator.entity.make_container') mock_make_container = mocker.patch('argenta.orchestrator.entity.make_container')
mocker.patch('argenta.orchestrator.entity.setup_dishka') mocker.patch('argenta.orchestrator.entity.setup_dishka')
mocker.patch.object(sample_app, 'run_polling') mocker.patch.object(sample_app, '_run_polling')
orchestrator = Orchestrator( orchestrator = Orchestrator(
arg_parser=mock_argparser, arg_parser=mock_argparser,
+126
View File
@@ -0,0 +1,126 @@
from argenta.app.presentation.renderers import RichRenderer, PlainRenderer
from argenta.app.registered_routers.entity import RegisteredRouters
from argenta.command.models import Command
from argenta.response import Response
from argenta.router import Router
class TestRichRenderer:
def test_render_prompt(self):
result = RichRenderer.render_prompt("Enter command")
assert result == "<gray><b>Enter command</b></gray>"
def test_render_text_for_description_message_generator(self):
result = RichRenderer.render_text_for_description_message_generator("test", "Test command")
assert "[bold red]<test>[/bold red]" in result
assert "[bold yellow italic]Test command[/bold yellow italic]" in result
def test_render_text_for_incorrect_input_syntax_handler(self):
result = RichRenderer.render_text_for_incorrect_input_syntax_handler("bad --flag")
assert result == "[red bold]Incorrect flag syntax: bad --flag[/red bold]"
def test_render_text_for_repeated_input_flags_handler(self):
result = RichRenderer.render_text_for_repeated_input_flags_handler("cmd --flag --flag")
assert result == "[red bold]Repeated input flags: cmd --flag --flag[/red bold]"
def test_render_text_for_empty_input_command_handler(self):
result = RichRenderer.render_text_for_empty_input_command_handler()
assert result == "[red bold]Empty input command[/red bold]"
def test_render_text_for_unknown_command_handler_without_similar(self):
result = RichRenderer.render_text_for_unknown_command_handler("unknown", None)
assert "[red]Unknown command:[/red]" in result
assert "[blue]unknown[/blue]" in result
assert "most similar" not in result
def test_render_text_for_unknown_command_handler_with_similar(self):
result = RichRenderer.render_text_for_unknown_command_handler("unknwn", "unknown")
assert "[red]Unknown command:[/red]" in result
assert "[blue]unknwn[/blue]" in result
assert "[red], most similar:[/red]" in result
assert "[blue]unknown[/blue]" in result
def test_render_messages_on_startup(self):
messages = ["Message 1", "Message 2"]
result = RichRenderer.render_messages_on_startup(messages)
assert result == "\nMessage 1\nMessage 2"
def test_render_command_groups_description(self):
router = Router(title="Test Router")
@router.command(Command("test", description="Test command"))
def handler(_: Response):
pass
registered_routers = RegisteredRouters()
registered_routers.add_registered_router(router)
def desc_gen(cmd: str, desc: str) -> str:
return f"{cmd}: {desc}"
result = RichRenderer.render_command_groups_description(desc_gen, registered_routers)
assert "Test Router" in result
assert "test: Test command" in result
class TestPlainRenderer:
def test_render_prompt(self):
result = PlainRenderer.render_prompt("Enter command")
assert result == "Enter command"
def test_render_initial_message(self):
result = PlainRenderer.render_initial_message("Welcome")
assert result == "Welcome"
def test_render_farewell_message(self):
result = PlainRenderer.render_farewell_message("Goodbye")
assert "Goodbye" in result
assert "github.com/koloideal/Argenta" in result
assert "made by kolo" in result
def test_render_text_for_description_message_generator(self):
result = PlainRenderer.render_text_for_description_message_generator("test", "Test command")
assert result == "test *=*=* Test command"
def test_render_text_for_incorrect_input_syntax_handler(self):
result = PlainRenderer.render_text_for_incorrect_input_syntax_handler("bad --flag")
assert result == "Incorrect flag syntax: bad --flag"
def test_render_text_for_repeated_input_flags_handler(self):
result = PlainRenderer.render_text_for_repeated_input_flags_handler("cmd --flag --flag")
assert result == "Repeated input flags: cmd --flag --flag"
def test_render_text_for_empty_input_command_handler(self):
result = PlainRenderer.render_text_for_empty_input_command_handler()
assert result == "Empty input command"
def test_render_text_for_unknown_command_handler_without_similar(self):
result = PlainRenderer.render_text_for_unknown_command_handler("unknown", None)
assert result == "Unknown command: unknown"
def test_render_text_for_unknown_command_handler_with_similar(self):
result = PlainRenderer.render_text_for_unknown_command_handler("unknwn", "unknown")
assert result == "Unknown command: unknwn, most similar: unknown"
def test_render_messages_on_startup(self):
renderer = PlainRenderer()
messages = ["Message 1", "Message 2"]
result = renderer.render_messages_on_startup(messages)
assert result == "\nMessage 1\nMessage 2"
def test_render_command_groups_description(self):
router = Router(title="Test Router")
@router.command(Command("test", description="Test command"))
def handler(_: Response):
pass
registered_routers = RegisteredRouters()
registered_routers.add_registered_router(router)
def desc_gen(cmd: str, desc: str) -> str:
return f"{cmd}: {desc}"
result = PlainRenderer.render_command_groups_description(desc_gen, registered_routers)
assert "Test Router" in result
assert "test: Test command" in result
+13 -14
View File
@@ -8,7 +8,6 @@ from argenta.command.flag import Flag, InputFlag
from argenta.command.flag.models import PossibleValues, ValidationStatus from argenta.command.flag.models import PossibleValues, ValidationStatus
from argenta.response.entity import Response from argenta.response.entity import Response
from argenta.router import Router from argenta.router import Router
from argenta.router.entity import _structuring_input_flags, _validate_func_args
from argenta.router.exceptions import ( from argenta.router.exceptions import (
RepeatedAliasNameException, RepeatedAliasNameException,
RepeatedFlagNameException, RepeatedFlagNameException,
@@ -57,7 +56,7 @@ def test_validate_func_args_raises_error_for_missing_response_parameter() -> Non
def handler() -> None: def handler() -> None:
pass pass
with pytest.raises(RequiredArgumentNotPassedException): with pytest.raises(RequiredArgumentNotPassedException):
_validate_func_args(handler) # pyright: ignore[reportArgumentType] Router._validate_func_args(handler) # pyright: ignore[reportArgumentType]
def test_validate_func_args_prints_warning_for_wrong_type_hint(capsys: CaptureFixture[str]) -> None: def test_validate_func_args_prints_warning_for_wrong_type_hint(capsys: CaptureFixture[str]) -> None:
@@ -67,7 +66,7 @@ def test_validate_func_args_prints_warning_for_wrong_type_hint(capsys: CaptureFi
def func(_response: NotResponse) -> None: def func(_response: NotResponse) -> None:
pass pass
_validate_func_args(func) Router._validate_func_args(func)
output = capsys.readouterr() output = capsys.readouterr()
@@ -77,7 +76,7 @@ def test_validate_func_args_prints_warning_for_wrong_type_hint(capsys: CaptureFi
def test_validate_func_args_accepts_missing_type_hint(capsys: CaptureFixture[str]) -> None: def test_validate_func_args_accepts_missing_type_hint(capsys: CaptureFixture[str]) -> None:
def func(response) -> None: # pyright: ignore[reportMissingParameterType, reportUnknownParameterType] def func(response) -> None: # pyright: ignore[reportMissingParameterType, reportUnknownParameterType]
pass pass
_validate_func_args(func) # pyright: ignore[reportUnknownArgumentType] Router._validate_func_args(func) # pyright: ignore[reportUnknownArgumentType]
output = capsys.readouterr() output = capsys.readouterr()
assert output.out == '' assert output.out == ''
@@ -90,19 +89,19 @@ def test_validate_func_args_accepts_missing_type_hint(capsys: CaptureFixture[str
def test_structuring_input_flags_marks_unregistered_flag_as_undefined() -> None: def test_structuring_input_flags_marks_unregistered_flag_as_undefined() -> None:
cmd = Command('cmd') cmd = Command('cmd')
input_flags = InputFlags([InputFlag('ssh', input_value='', status=None)]) input_flags = InputFlags([InputFlag('ssh', input_value='', status=None)])
assert _structuring_input_flags(cmd, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='', status=ValidationStatus.UNDEFINED)]) assert Router._structuring_input_flags(cmd, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='', status=ValidationStatus.UNDEFINED)])
def test_structuring_input_flags_marks_unregistered_flag_with_value_as_undefined() -> None: def test_structuring_input_flags_marks_unregistered_flag_with_value_as_undefined() -> None:
cmd = Command('cmd') cmd = Command('cmd')
input_flags = InputFlags([InputFlag('ssh', input_value='some', status=None)]) input_flags = InputFlags([InputFlag('ssh', input_value='some', status=None)])
assert _structuring_input_flags(cmd, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='some', status=ValidationStatus.UNDEFINED)]) assert Router._structuring_input_flags(cmd, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='some', status=ValidationStatus.UNDEFINED)])
def test_structuring_input_flags_marks_flag_undefined_when_different_flag_registered() -> None: def test_structuring_input_flags_marks_flag_undefined_when_different_flag_registered() -> None:
cmd = Command('cmd', flags=Flag('port')) cmd = Command('cmd', flags=Flag('port'))
input_flags = InputFlags([InputFlag('ssh', input_value='some2', status=None)]) input_flags = InputFlags([InputFlag('ssh', input_value='some2', status=None)])
assert _structuring_input_flags(cmd, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='some2', status=ValidationStatus.UNDEFINED)]) assert Router._structuring_input_flags(cmd, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='some2', status=ValidationStatus.UNDEFINED)])
# ============================================================================ # ============================================================================
@@ -113,19 +112,19 @@ def test_structuring_input_flags_marks_flag_undefined_when_different_flag_regist
def test_structuring_input_flags_marks_flag_invalid_when_value_provided_for_neither() -> None: def test_structuring_input_flags_marks_flag_invalid_when_value_provided_for_neither() -> None:
command = Command('cmd', flags=Flag('ssh', possible_values=PossibleValues.NEITHER)) command = Command('cmd', flags=Flag('ssh', possible_values=PossibleValues.NEITHER))
input_flags = InputFlags([InputFlag('ssh', input_value='some3', status=None)]) input_flags = InputFlags([InputFlag('ssh', input_value='some3', status=None)])
assert _structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='some3', status=ValidationStatus.INVALID)]) assert Router._structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='some3', status=ValidationStatus.INVALID)])
def test_structuring_input_flags_marks_flag_invalid_when_value_not_matching_regex() -> None: def test_structuring_input_flags_marks_flag_invalid_when_value_not_matching_regex() -> None:
command = Command('cmd', flags=Flag('ssh', possible_values=re.compile(r'some[1-5]$'))) command = Command('cmd', flags=Flag('ssh', possible_values=re.compile(r'some[1-5]$')))
input_flags = InputFlags([InputFlag('ssh', input_value='some40', status=None)]) input_flags = InputFlags([InputFlag('ssh', input_value='some40', status=None)])
assert _structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='some40', status=ValidationStatus.INVALID)]) assert Router._structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='some40', status=ValidationStatus.INVALID)])
def test_structuring_input_flags_marks_flag_invalid_when_value_not_in_list() -> None: def test_structuring_input_flags_marks_flag_invalid_when_value_not_in_list() -> None:
command = Command('cmd', flags=Flag('ssh', possible_values=['example'])) command = Command('cmd', flags=Flag('ssh', possible_values=['example']))
input_flags = InputFlags([InputFlag('ssh', input_value='example2', status=None)]) input_flags = InputFlags([InputFlag('ssh', input_value='example2', status=None)])
assert _structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='example2', status=ValidationStatus.INVALID)]) assert Router._structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='example2', status=ValidationStatus.INVALID)])
# ============================================================================ # ============================================================================
@@ -136,25 +135,25 @@ def test_structuring_input_flags_marks_flag_invalid_when_value_not_in_list() ->
def test_structuring_input_flags_marks_registered_flag_as_valid() -> None: def test_structuring_input_flags_marks_registered_flag_as_valid() -> None:
command = Command('cmd', flags=Flag('port')) command = Command('cmd', flags=Flag('port'))
input_flags = InputFlags([InputFlag('port', input_value='some2', status=None)]) input_flags = InputFlags([InputFlag('port', input_value='some2', status=None)])
assert _structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('port', input_value='some2', status=ValidationStatus.VALID)]) assert Router._structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('port', input_value='some2', status=ValidationStatus.VALID)])
def test_structuring_input_flags_marks_flag_valid_when_value_in_list() -> None: def test_structuring_input_flags_marks_flag_valid_when_value_in_list() -> None:
command = Command('cmd', flags=Flag('port', possible_values=['some2', 'some3'])) command = Command('cmd', flags=Flag('port', possible_values=['some2', 'some3']))
input_flags = InputFlags([InputFlag('port', input_value='some2', status=None)]) input_flags = InputFlags([InputFlag('port', input_value='some2', status=None)])
assert _structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('port', input_value='some2', status=ValidationStatus.VALID)]) assert Router._structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('port', input_value='some2', status=ValidationStatus.VALID)])
def test_structuring_input_flags_marks_flag_valid_when_value_matches_regex() -> None: def test_structuring_input_flags_marks_flag_valid_when_value_matches_regex() -> None:
command = Command('cmd', flags=Flag('ssh', possible_values=re.compile(r'more[1-5]$'))) command = Command('cmd', flags=Flag('ssh', possible_values=re.compile(r'more[1-5]$')))
input_flags = InputFlags([InputFlag('ssh', input_value='more5', status=None)]) input_flags = InputFlags([InputFlag('ssh', input_value='more5', status=None)])
assert _structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='more5', status=ValidationStatus.VALID)]) assert Router._structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='more5', status=ValidationStatus.VALID)])
def test_structuring_input_flags_marks_flag_valid_when_empty_value_for_neither() -> None: def test_structuring_input_flags_marks_flag_valid_when_empty_value_for_neither() -> None:
command = Command('cmd', flags=Flag('ssh', possible_values=PossibleValues.NEITHER)) command = Command('cmd', flags=Flag('ssh', possible_values=PossibleValues.NEITHER))
input_flags = InputFlags([InputFlag('ssh', input_value='', status=None)]) input_flags = InputFlags([InputFlag('ssh', input_value='', status=None)])
assert _structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='', status=ValidationStatus.VALID)]) assert Router._structuring_input_flags(command, input_flags).input_flags == InputFlags([InputFlag('ssh', input_value='', status=ValidationStatus.VALID)])
# ============================================================================ # ============================================================================
+145
View File
@@ -0,0 +1,145 @@
from pytest_mock import MockerFixture
from argenta.app.presentation.viewers import Viewer
from argenta.app.presentation.renderers import PlainRenderer
from argenta.app.dividing_line.models import StaticDividingLine, DynamicDividingLine
from argenta.app.registered_routers.entity import RegisteredRouters
from argenta.command.models import Command
from argenta.response import Response
from argenta.router import Router
class TestViewer:
def test_viewer_initialization(self, mocker: MockerFixture):
printer = mocker.Mock()
renderer = PlainRenderer()
dividing_line = StaticDividingLine()
viewer = Viewer(printer, renderer, dividing_line, False)
assert viewer._printer == printer
assert viewer._renderer == renderer
assert viewer._dividing_line == dividing_line
assert viewer._override_system_messages is False
def test_view_initial_message(self, mocker: MockerFixture):
printer = mocker.Mock()
renderer = PlainRenderer()
viewer = Viewer(printer, renderer, None, False)
viewer.view_initial_message("Welcome")
printer.assert_called_once_with("Welcome")
def test_view_messages_on_startup(self, mocker: MockerFixture):
printer = mocker.Mock()
renderer = PlainRenderer()
viewer = Viewer(printer, renderer, None, False)
messages = ["Message 1", "Message 2"]
viewer.view_messages_on_startup(messages)
printer.assert_called_once()
call_arg = printer.call_args[0][0]
assert "Message 1" in call_arg
assert "Message 2" in call_arg
def test_view_command_groups_description(self, mocker: MockerFixture):
printer = mocker.Mock()
renderer = PlainRenderer()
viewer = Viewer(printer, renderer, None, False)
router = Router(title="Test Router")
@router.command(Command("test", description="Test command"))
def handler(_: Response):
pass
registered_routers = RegisteredRouters()
registered_routers.add_registered_router(router)
def desc_gen(cmd: str, desc: str) -> str:
return f"{cmd}: {desc}"
viewer.view_command_groups_description(desc_gen, registered_routers)
printer.assert_called_once()
call_arg = printer.call_args[0][0]
assert "Test Router" in call_arg
assert "test: Test command" in call_arg
def test_view_framed_text_with_no_dividing_line(self, mocker: MockerFixture):
printer = mocker.Mock()
renderer = PlainRenderer()
viewer = Viewer(printer, renderer, None, False)
output_generator = mocker.Mock()
viewer.view_framed_text_from_generator(output_generator)
output_generator.assert_called_once()
def test_view_framed_text_with_static_dividing_line(self, mocker: MockerFixture):
printer = mocker.Mock()
renderer = PlainRenderer()
dividing_line = StaticDividingLine("=")
viewer = Viewer(printer, renderer, dividing_line, False)
output_generator = mocker.Mock()
viewer.view_framed_text_from_generator(output_generator)
output_generator.assert_called_once()
assert printer.call_count >= 2
def test_capture_stdout(self, mocker: MockerFixture):
printer = mocker.Mock()
renderer = PlainRenderer()
viewer = Viewer(printer, renderer, None, False)
def test_func():
print("test output")
result = viewer._capture_stdout(test_func)
assert "test output" in result
def test_capture_stdout_reuses_buffer(self, mocker: MockerFixture):
printer = mocker.Mock()
renderer = PlainRenderer()
viewer = Viewer(printer, renderer, None, False)
def test_func1():
print("output 1")
def test_func2():
print("output 2")
result1 = viewer._capture_stdout(test_func1)
result2 = viewer._capture_stdout(test_func2)
assert "output 1" in result1
assert "output 1" not in result2
assert "output 2" in result2
def test_view_framed_text_with_dynamic_dividing_line(self, mocker: MockerFixture):
printer = mocker.Mock()
renderer = PlainRenderer()
dividing_line = DynamicDividingLine("=")
viewer = Viewer(printer, renderer, dividing_line, False)
def output_generator():
print("test output")
viewer.view_framed_text_from_generator(output_generator)
assert printer.call_count >= 2
def test_view_framed_text_with_router_stdout_redirect(self, mocker: MockerFixture):
printer = mocker.Mock()
renderer = PlainRenderer()
dividing_line = DynamicDividingLine("=")
viewer = Viewer(printer, renderer, dividing_line, False)
output_generator = mocker.Mock()
viewer.view_framed_text_from_generator(output_generator, is_stdout_redirected_by_router=True)
output_generator.assert_called_once()
assert printer.call_count >= 2