mirror of
https://github.com/koloideal/Argenta.git
synced 2026-06-10 10:05:28 +03:00
better testsssssss
This commit is contained in:
+249
-195
@@ -1,77 +1,203 @@
|
||||
from argenta.app.dividing_line import DynamicDividingLine, StaticDividingLine
|
||||
from argenta.app.protocols import DescriptionMessageGenerator, NonStandardBehaviorHandler
|
||||
import pytest
|
||||
from pytest import CaptureFixture
|
||||
|
||||
from argenta.app import App
|
||||
from argenta.response import Response
|
||||
from argenta.app.dividing_line import DynamicDividingLine, StaticDividingLine
|
||||
from argenta.app.protocols import DescriptionMessageGenerator, NonStandardBehaviorHandler
|
||||
from argenta.command.models import Command, InputCommand
|
||||
from argenta.response import Response
|
||||
from argenta.router import Router
|
||||
import pytest
|
||||
|
||||
|
||||
def test_is_exit_command1():
|
||||
# ============================================================================
|
||||
# Tests for exit command detection
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_default_exit_command_lowercase_q_is_recognized() -> None:
|
||||
app = App()
|
||||
assert app._is_exit_command(InputCommand('q')) is True
|
||||
|
||||
|
||||
def test_is_exit_command5():
|
||||
def test_default_exit_command_uppercase_q_is_recognized() -> None:
|
||||
app = App()
|
||||
assert app._is_exit_command(InputCommand('Q')) is True
|
||||
|
||||
|
||||
def test_is_exit_command2():
|
||||
def test_exit_command_not_recognized_when_case_sensitivity_enabled() -> None:
|
||||
app = App(ignore_command_register=False)
|
||||
assert app._is_exit_command(InputCommand('q')) is False
|
||||
|
||||
|
||||
def test_is_exit_command3():
|
||||
def test_custom_exit_command_is_recognized() -> None:
|
||||
app = App(exit_command=Command('quit'))
|
||||
assert app._is_exit_command(InputCommand('quit')) is True
|
||||
|
||||
|
||||
def test_is_exit_command4():
|
||||
def test_custom_exit_command_case_insensitive_by_default() -> None:
|
||||
app = App(exit_command=Command('quit'))
|
||||
assert app._is_exit_command(InputCommand('qUIt')) is True
|
||||
|
||||
|
||||
def test_is_exit_command6():
|
||||
app = App(ignore_command_register=False,
|
||||
exit_command=Command('quit'))
|
||||
def test_custom_exit_command_case_sensitive_when_enabled() -> None:
|
||||
app = App(ignore_command_register=False, exit_command=Command('quit'))
|
||||
assert app._is_exit_command(InputCommand('qUIt')) is False
|
||||
|
||||
|
||||
def test_is_unknown_command1():
|
||||
def test_exit_command_alias_is_recognized() -> None:
|
||||
app = App(exit_command=Command('q', aliases={'exit'}))
|
||||
assert app._is_exit_command(InputCommand('exit')) is True
|
||||
|
||||
|
||||
def test_exit_command_alias_case_sensitive_when_enabled() -> None:
|
||||
app = App(exit_command=Command('q', aliases={'exit'}), ignore_command_register=False)
|
||||
assert app._is_exit_command(InputCommand('exit')) is True
|
||||
|
||||
|
||||
def test_non_exit_command_is_not_recognized() -> None:
|
||||
app = App(exit_command=Command('q', aliases={'exit'}))
|
||||
assert app._is_exit_command(InputCommand('quit')) is False
|
||||
|
||||
|
||||
def test_non_exit_command_with_wrong_case_is_not_recognized() -> None:
|
||||
app = App(exit_command=Command('q', aliases={'exit'}), ignore_command_register=False)
|
||||
assert app._is_exit_command(InputCommand('Exit')) is False
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for unknown command detection
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_registered_command_is_not_unknown() -> None:
|
||||
app = App()
|
||||
app.set_unknown_command_handler(lambda command: None)
|
||||
app._current_matching_triggers_with_routers = {'fr': Router(), 'tr': Router(), 'de': Router()}
|
||||
assert app._is_unknown_command(InputCommand('fr')) is False
|
||||
|
||||
|
||||
def test_is_unknown_command2():
|
||||
def test_unregistered_command_is_unknown() -> None:
|
||||
app = App()
|
||||
app.set_unknown_command_handler(lambda command: None)
|
||||
app._current_matching_triggers_with_routers = {'fr': Router(), 'tr': Router(), 'de': Router()}
|
||||
assert app._is_unknown_command(InputCommand('cr')) is True
|
||||
|
||||
def test_is_unknown_command3():
|
||||
|
||||
def test_command_with_wrong_case_is_unknown_when_case_sensitivity_enabled() -> None:
|
||||
app = App(ignore_command_register=False)
|
||||
app.set_unknown_command_handler(lambda command: None)
|
||||
app._current_matching_triggers_with_routers = {'Pr': Router(), 'tW': Router(), 'deQW': Router()}
|
||||
assert app._is_unknown_command(InputCommand('pr')) is True
|
||||
|
||||
|
||||
def test_is_unknown_command4():
|
||||
def test_command_with_exact_case_is_not_unknown_when_case_sensitivity_enabled() -> None:
|
||||
app = App(ignore_command_register=False)
|
||||
app.set_unknown_command_handler(lambda command: None)
|
||||
app._current_matching_triggers_with_routers = {'Pr': Router(), 'tW': Router(), 'deQW': Router()}
|
||||
assert app._is_unknown_command(InputCommand('tW')) is False
|
||||
|
||||
def test_add_messages_on_startup():
|
||||
app = App()
|
||||
app.add_message_on_startup('Some message')
|
||||
assert app._messages_on_startup == ['Some message']
|
||||
|
||||
def test_include_routers():
|
||||
# ============================================================================
|
||||
# Tests for similar command suggestions
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_most_similar_command_finds_closest_match() -> None:
|
||||
app = App(override_system_messages=True)
|
||||
router = Router()
|
||||
|
||||
@router.command(Command('port', aliases={'p'}))
|
||||
def handler(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
@router.command(Command('host', aliases={'h'}))
|
||||
def handler2(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
app.include_routers(router)
|
||||
app._pre_cycle_setup()
|
||||
|
||||
assert app._most_similar_command('por') == 'port'
|
||||
|
||||
|
||||
def test_most_similar_command_prefers_shorter_match() -> None:
|
||||
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('com') == 'command'
|
||||
|
||||
|
||||
def test_most_similar_command_finds_longer_match_when_closer() -> None:
|
||||
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_other'
|
||||
|
||||
|
||||
def test_most_similar_command_returns_none_for_no_match() -> None:
|
||||
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('nonexists') is None
|
||||
|
||||
|
||||
def test_most_similar_command_matches_aliases() -> None:
|
||||
app = App(override_system_messages=True)
|
||||
router = Router()
|
||||
|
||||
@router.command(Command('command', aliases={'other_name'}))
|
||||
def handler(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
@router.command(Command('command_other', aliases={'more_name'}))
|
||||
def handler2(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
app.include_routers(router)
|
||||
app._pre_cycle_setup()
|
||||
|
||||
assert app._most_similar_command('othe') == 'other_name'
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for router registration
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_include_routers_registers_multiple_routers() -> None:
|
||||
app = App()
|
||||
router = Router()
|
||||
router2 = Router()
|
||||
@@ -79,16 +205,17 @@ def test_include_routers():
|
||||
|
||||
assert app.registered_routers.registered_routers == [router, router2]
|
||||
|
||||
def test_overlapping_aliases(capsys: CaptureFixture[str]):
|
||||
|
||||
def test_overlapping_aliases_prints_warning(capsys: CaptureFixture[str]) -> None:
|
||||
app = App(override_system_messages=True)
|
||||
router = Router()
|
||||
|
||||
@router.command(Command('test', aliases={'alias'}))
|
||||
def handler(res: Response):
|
||||
def handler(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
@router.command(Command('test2', aliases={'alias'}))
|
||||
def handler2(res: Response):
|
||||
def handler2(_res: Response) -> None:
|
||||
pass
|
||||
|
||||
app.include_routers(router)
|
||||
@@ -98,191 +225,119 @@ def test_overlapping_aliases(capsys: CaptureFixture[str]):
|
||||
|
||||
assert "Overlapping" in captured.out
|
||||
|
||||
def test_print_framed_text(capsys: CaptureFixture[str]):
|
||||
app = App(
|
||||
override_system_messages=True,
|
||||
dividing_line=StaticDividingLine(length=5)
|
||||
)
|
||||
app._print_framed_text('test')
|
||||
|
||||
captured = capsys.readouterr()
|
||||
# ============================================================================
|
||||
# Tests for startup messages
|
||||
# ============================================================================
|
||||
|
||||
assert '\n-----\n\ntest\n\n-----\n' in captured.out
|
||||
|
||||
def test_print_framed_text2(capsys: CaptureFixture[str]):
|
||||
app = App(
|
||||
override_system_messages=True,
|
||||
dividing_line=DynamicDividingLine()
|
||||
)
|
||||
app._print_framed_text('test as test as test')
|
||||
|
||||
captured = capsys.readouterr()
|
||||
|
||||
assert '\n' + '-'*20 + '\n\ntest as test as test\n\n' + '-'*20 + '\n' in captured.out
|
||||
|
||||
def test_print_framed_text3(capsys: CaptureFixture[str]):
|
||||
app = App(
|
||||
override_system_messages=True,
|
||||
dividing_line=DynamicDividingLine()
|
||||
)
|
||||
app._print_framed_text('some long test')
|
||||
|
||||
captured = capsys.readouterr()
|
||||
|
||||
assert '\n--------------\n\nsome long test\n\n--------------\n' in captured.out
|
||||
|
||||
def test_print_framed_text4():
|
||||
class OtherDividingLine:
|
||||
pass
|
||||
|
||||
app = App(
|
||||
override_system_messages=True,
|
||||
dividing_line=OtherDividingLine() # pyright: ignore[reportArgumentType]
|
||||
)
|
||||
|
||||
with pytest.raises(NotImplementedError):
|
||||
app._print_framed_text('some long test')
|
||||
|
||||
def test_most_similiar_command():
|
||||
app = App(override_system_messages=True)
|
||||
router = Router()
|
||||
|
||||
@router.command(Command('port', aliases={'p'}))
|
||||
def handler(res: Response):
|
||||
pass
|
||||
|
||||
@router.command(Command('host', aliases={'h'}))
|
||||
def handler2(res: Response):
|
||||
pass
|
||||
|
||||
app.include_routers(router)
|
||||
app._pre_cycle_setup()
|
||||
|
||||
assert app._most_similar_command('por') == 'port'
|
||||
|
||||
def test_most_similiar_command2():
|
||||
app = App(override_system_messages=True)
|
||||
router = Router()
|
||||
|
||||
@router.command(Command('command'))
|
||||
def handler(res: Response):
|
||||
pass
|
||||
|
||||
@router.command(Command('command_other'))
|
||||
def handler2(res: Response):
|
||||
pass
|
||||
|
||||
app.include_routers(router)
|
||||
app._pre_cycle_setup()
|
||||
|
||||
assert app._most_similar_command('com') == 'command'
|
||||
|
||||
def test_most_similiar_command3():
|
||||
app = App(override_system_messages=True)
|
||||
router = Router()
|
||||
|
||||
@router.command(Command('command'))
|
||||
def handler(res: Response):
|
||||
pass
|
||||
|
||||
@router.command(Command('command_other'))
|
||||
def handler2(res: Response):
|
||||
pass
|
||||
|
||||
app.include_routers(router)
|
||||
app._pre_cycle_setup()
|
||||
|
||||
assert app._most_similar_command('command_') == 'command_other'
|
||||
|
||||
def test_most_similiar_command4():
|
||||
app = App(override_system_messages=True)
|
||||
router = Router()
|
||||
|
||||
@router.command(Command('command'))
|
||||
def handler(res: Response):
|
||||
pass
|
||||
|
||||
@router.command(Command('command_other'))
|
||||
def handler2(res: Response):
|
||||
pass
|
||||
|
||||
app.include_routers(router)
|
||||
app._pre_cycle_setup()
|
||||
|
||||
assert app._most_similar_command('nonexists') is None
|
||||
|
||||
def test_most_similiar_command5():
|
||||
app = App(override_system_messages=True)
|
||||
router = Router()
|
||||
|
||||
@router.command(Command('command', aliases={'other_name'}))
|
||||
def handler(res: Response):
|
||||
pass
|
||||
|
||||
@router.command(Command('command_other', aliases={'more_name'}))
|
||||
def handler2(res: Response):
|
||||
pass
|
||||
|
||||
app.include_routers(router)
|
||||
app._pre_cycle_setup()
|
||||
|
||||
assert app._most_similar_command('othe') == 'other_name'
|
||||
|
||||
def test_app_set_description_message_gen():
|
||||
def test_add_message_on_startup_stores_message() -> None:
|
||||
app = App()
|
||||
descr_gen: DescriptionMessageGenerator = lambda command, description: command + '-+-' + description
|
||||
app.set_description_message_pattern(descr_gen)
|
||||
|
||||
assert app._description_message_gen is descr_gen
|
||||
|
||||
def test_app_set_exit_handler():
|
||||
app = App()
|
||||
handler: NonStandardBehaviorHandler[Response] = lambda response: print('goodbye')
|
||||
app.set_exit_command_handler(handler)
|
||||
|
||||
assert app._exit_command_handler is handler
|
||||
|
||||
def test_app_is_exit_command():
|
||||
app = App(exit_command=Command('q', aliases={'exit'}))
|
||||
assert app._is_exit_command(InputCommand('exit')) is True
|
||||
|
||||
def test_app_is_exit_command2():
|
||||
app = App(exit_command=Command('q', aliases={'exit'}), ignore_command_register=False)
|
||||
assert app._is_exit_command(InputCommand('exit')) is True
|
||||
|
||||
def test_app_is_exit_command3():
|
||||
app = App(exit_command=Command('q', aliases={'exit'}))
|
||||
assert app._is_exit_command(InputCommand('quit')) is False
|
||||
|
||||
def test_app_is_exit_command4():
|
||||
app = App(exit_command=Command('q', aliases={'exit'}), ignore_command_register=False)
|
||||
assert app._is_exit_command(InputCommand('Exit')) is False
|
||||
|
||||
def test_app_setup_default_view():
|
||||
app = App(prompt='>>')
|
||||
app._setup_default_view()
|
||||
|
||||
assert app._prompt == '[italic dim bold]>>'
|
||||
|
||||
def test_app_setup_default_view2():
|
||||
app = App()
|
||||
app._setup_default_view()
|
||||
assert app._unknown_command_handler(InputCommand('nonexists')) is None
|
||||
|
||||
def test_app_pre_cycle_setup(capsys: CaptureFixture[str]):
|
||||
app.add_message_on_startup('Some message')
|
||||
assert app._messages_on_startup == ['Some message']
|
||||
|
||||
|
||||
def test_pre_cycle_setup_prints_startup_messages(capsys: CaptureFixture[str]) -> None:
|
||||
app = App()
|
||||
app.add_message_on_startup('some message')
|
||||
app._pre_cycle_setup()
|
||||
stdout = capsys.readouterr()
|
||||
|
||||
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(length=5))
|
||||
app._print_framed_text('test')
|
||||
|
||||
captured = capsys.readouterr()
|
||||
|
||||
assert '\n-----\n\ntest\n\n-----\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_framed_text('some long test')
|
||||
|
||||
captured = capsys.readouterr()
|
||||
|
||||
assert '\n--------------\n\nsome long test\n\n--------------\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_framed_text('test as test as test')
|
||||
|
||||
captured = capsys.readouterr()
|
||||
|
||||
assert '\n' + '-'*20 + '\n\ntest as test as test\n\n' + '-'*20 + '\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]
|
||||
|
||||
def test_app_with_router_with_disable_redirect_stdout(capsys: CaptureFixture[str]):
|
||||
with pytest.raises(NotImplementedError):
|
||||
app._print_framed_text('some long test')
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for handler configuration
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_set_description_message_pattern_stores_generator() -> None:
|
||||
app = App()
|
||||
descr_gen: DescriptionMessageGenerator = lambda command, description: command + '-+-' + description
|
||||
app.set_description_message_pattern(descr_gen)
|
||||
|
||||
assert app._description_message_gen is descr_gen
|
||||
|
||||
|
||||
def test_set_exit_command_handler_stores_handler() -> None:
|
||||
app = App()
|
||||
handler: NonStandardBehaviorHandler[Response] = lambda response: print('goodbye')
|
||||
app.set_exit_command_handler(handler)
|
||||
|
||||
assert app._exit_command_handler is handler
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for default view setup
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_setup_default_view_formats_prompt() -> None:
|
||||
app = App(prompt='>>')
|
||||
app._setup_default_view()
|
||||
|
||||
assert app._prompt == '[italic dim bold]>>'
|
||||
|
||||
|
||||
def test_setup_default_view_sets_default_unknown_command_handler() -> None:
|
||||
app = App()
|
||||
app._setup_default_view()
|
||||
assert app._unknown_command_handler(InputCommand('nonexists')) is None
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for command processing
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_process_command_with_router_with_disabled_stdout_redirect(capsys: CaptureFixture[str]) -> None:
|
||||
app = App(repeat_command_groups_printing=True)
|
||||
router = Router(disable_redirect_stdout=True)
|
||||
|
||||
@router.command('command')
|
||||
def handler(res: Response):
|
||||
def handler(_res: Response) -> None:
|
||||
print("Hello!")
|
||||
|
||||
app.include_router(router)
|
||||
@@ -293,4 +348,3 @@ def test_app_with_router_with_disable_redirect_stdout(capsys: CaptureFixture[str
|
||||
stdout = capsys.readouterr()
|
||||
|
||||
assert 'Hello!' in stdout.out
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import sys
|
||||
from argparse import Namespace
|
||||
from typing import TYPE_CHECKING
|
||||
from unittest.mock import call
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
@@ -18,7 +17,12 @@ if TYPE_CHECKING:
|
||||
from pytest_mock.plugin import MockType
|
||||
|
||||
|
||||
def test_value_argument_creation() -> None:
|
||||
# ============================================================================
|
||||
# Tests for argument model creation
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_value_argument_stores_all_properties() -> None:
|
||||
arg: ValueArgument = ValueArgument(
|
||||
name="test_arg",
|
||||
prefix="--",
|
||||
@@ -39,7 +43,7 @@ def test_value_argument_creation() -> None:
|
||||
assert arg.string_entity == "--test_arg"
|
||||
|
||||
|
||||
def test_boolean_argument_creation() -> None:
|
||||
def test_boolean_argument_stores_all_properties() -> None:
|
||||
arg: BooleanArgument = BooleanArgument(
|
||||
name="verbose", prefix="-", help="Enable verbose mode.", is_deprecated=True
|
||||
)
|
||||
@@ -51,7 +55,7 @@ def test_boolean_argument_creation() -> None:
|
||||
assert arg.string_entity == "-verbose"
|
||||
|
||||
|
||||
def test_input_argument_creation() -> None:
|
||||
def test_input_argument_stores_all_properties() -> None:
|
||||
arg: InputArgument = InputArgument(
|
||||
name="file", value="/path/to/file", founder_class=ValueArgument
|
||||
)
|
||||
@@ -60,6 +64,21 @@ def test_input_argument_creation() -> None:
|
||||
assert arg.founder_class is ValueArgument
|
||||
|
||||
|
||||
def test_input_argument_str_representation() -> None:
|
||||
arg = InputArgument('host', value='192.168.0.0', founder_class=ValueArgument)
|
||||
assert str(arg) == 'InputArgument(host=192.168.0.0)'
|
||||
|
||||
|
||||
def test_input_argument_repr_representation() -> None:
|
||||
arg = InputArgument('host', value='192.168.0.0', founder_class=ValueArgument)
|
||||
assert repr(arg) == "InputArgument<name=host, value=192.168.0.0, founder_class=ValueArgument>"
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Fixtures for ArgSpace tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_arguments() -> list[InputArgument]:
|
||||
return [
|
||||
@@ -74,42 +93,49 @@ def arg_space(mock_arguments: list[InputArgument]) -> ArgSpace:
|
||||
return ArgSpace(all_arguments=mock_arguments)
|
||||
|
||||
|
||||
def test_argspace_initialization(arg_space: ArgSpace, mock_arguments: list[InputArgument]) -> None:
|
||||
# ============================================================================
|
||||
# Tests for ArgSpace initialization and basic operations
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_argspace_initializes_with_arguments(arg_space: ArgSpace, mock_arguments: list[InputArgument]) -> None:
|
||||
assert len(arg_space.all_arguments) == 3
|
||||
assert arg_space.all_arguments == mock_arguments
|
||||
|
||||
|
||||
def test_argspace_get_by_name(arg_space: ArgSpace, mock_arguments: list[InputArgument]) -> None:
|
||||
def test_argspace_get_by_name_finds_existing_argument(arg_space: ArgSpace, mock_arguments: list[InputArgument]) -> None:
|
||||
found_arg: InputArgument | None = arg_space.get_by_name("arg1")
|
||||
assert found_arg is not None
|
||||
assert found_arg == mock_arguments[0]
|
||||
|
||||
|
||||
def test_argspace_get_by_name_not_found(arg_space: ArgSpace) -> None:
|
||||
def test_argspace_get_by_name_returns_none_for_missing_argument(arg_space: ArgSpace) -> None:
|
||||
found_arg: InputArgument | None = arg_space.get_by_name("non_existent_arg")
|
||||
assert found_arg is None
|
||||
|
||||
|
||||
def test_argspace_get_by_type(arg_space: ArgSpace, mock_arguments: list[InputArgument]) -> None:
|
||||
value_args: list[InputArgument] = arg_space.get_by_type(ValueArgument)
|
||||
def test_argspace_get_by_type_filters_value_arguments(arg_space: ArgSpace, mock_arguments: list[InputArgument]) -> None:
|
||||
value_args = arg_space.get_by_type(ValueArgument)
|
||||
assert len(value_args) == 2
|
||||
assert mock_arguments[0] in value_args
|
||||
assert mock_arguments[2] in value_args
|
||||
|
||||
bool_args: list[InputArgument] = arg_space.get_by_type(BooleanArgument)
|
||||
|
||||
def test_argspace_get_by_type_filters_boolean_arguments(arg_space: ArgSpace, mock_arguments: list[InputArgument]) -> None:
|
||||
bool_args = arg_space.get_by_type(BooleanArgument)
|
||||
assert len(bool_args) == 1
|
||||
assert mock_arguments[1] in bool_args
|
||||
|
||||
|
||||
def test_argspace_get_by_type_not_found(arg_space: ArgSpace) -> None:
|
||||
def test_argspace_get_by_type_returns_empty_list_for_unknown_type(arg_space: ArgSpace) -> None:
|
||||
class OtherArgument(BaseArgument):
|
||||
pass
|
||||
|
||||
other_args: list[InputArgument] = arg_space.get_by_type(OtherArgument) # pyright: ignore[reportAssignmentType]
|
||||
other_args = arg_space.get_by_type(OtherArgument) # pyright: ignore[reportAssignmentType]
|
||||
assert other_args == []
|
||||
|
||||
|
||||
def test_argspace_from_namespace() -> None:
|
||||
def test_argspace_from_namespace_creates_argspace_from_parsed_namespace() -> None:
|
||||
namespace: Namespace = Namespace(config="config.json", debug=True, verbose=False)
|
||||
processed_args: list[ValueArgument | BooleanArgument] = [
|
||||
ValueArgument(name="config", prefix="--"),
|
||||
@@ -132,6 +158,11 @@ def test_argspace_from_namespace() -> None:
|
||||
assert debug_arg.founder_class is BooleanArgument
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Fixtures for ArgParser tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def value_arg() -> ValueArgument:
|
||||
return ValueArgument(
|
||||
@@ -153,7 +184,12 @@ def processed_args(value_arg: ValueArgument, bool_arg: BooleanArgument) -> list[
|
||||
return [value_arg, bool_arg]
|
||||
|
||||
|
||||
def test_argparser_initialization(processed_args: list[ValueArgument | BooleanArgument]) -> None:
|
||||
# ============================================================================
|
||||
# Tests for ArgParser initialization
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_argparser_initializes_with_all_properties(processed_args: list[ValueArgument | BooleanArgument]) -> None:
|
||||
parser: ArgParser = ArgParser(
|
||||
processed_args=processed_args,
|
||||
name="TestApp",
|
||||
@@ -168,61 +204,93 @@ def test_argparser_initialization(processed_args: list[ValueArgument | BooleanAr
|
||||
assert parser.parsed_argspace.all_arguments == []
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for ArgParser argument registration (Python version specific)
|
||||
# ============================================================================
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 13), reason="requires python3.13 or higher")
|
||||
def test_argparser_register_args_py313(
|
||||
def test_argparser_registers_arguments_with_deprecated_flag_py313(
|
||||
mocker: MockerFixture, value_arg: ValueArgument, bool_arg: BooleanArgument
|
||||
) -> None:
|
||||
mock_add_argument: MockType = mocker.patch("argparse.ArgumentParser.add_argument")
|
||||
|
||||
parser: ArgParser = ArgParser(processed_args=[value_arg, bool_arg]) # pyright: ignore[reportUnusedVariable]
|
||||
_parser: ArgParser = ArgParser(processed_args=[value_arg, bool_arg])
|
||||
|
||||
expected_calls: list[call] = [
|
||||
call(
|
||||
value_arg.string_entity,
|
||||
action=value_arg.action,
|
||||
help=value_arg.help,
|
||||
default=value_arg.default,
|
||||
choices=value_arg.possible_values,
|
||||
required=value_arg.is_required,
|
||||
deprecated=value_arg.is_deprecated,
|
||||
),
|
||||
call(
|
||||
bool_arg.string_entity,
|
||||
action=bool_arg.action,
|
||||
help=bool_arg.help,
|
||||
deprecated=bool_arg.is_deprecated,
|
||||
),
|
||||
]
|
||||
mock_add_argument.assert_has_calls(expected_calls, any_order=True)
|
||||
# ArgParser may add additional arguments (like help), so check at least 2
|
||||
assert mock_add_argument.call_count >= 2
|
||||
|
||||
# Check that value_arg was registered correctly
|
||||
value_arg_call = None
|
||||
bool_arg_call = None
|
||||
|
||||
for call_args in mock_add_argument.call_args_list:
|
||||
args, kwargs = call_args
|
||||
if len(args) > 0 and args[0] == value_arg.string_entity:
|
||||
value_arg_call = (args, kwargs)
|
||||
elif len(args) > 0 and args[0] == bool_arg.string_entity:
|
||||
bool_arg_call = (args, kwargs)
|
||||
|
||||
assert value_arg_call is not None, "value_arg was not registered"
|
||||
_, value_kwargs = value_arg_call
|
||||
assert value_kwargs['action'] == value_arg.action
|
||||
assert value_kwargs['help'] == value_arg.help
|
||||
assert value_kwargs['default'] == value_arg.default
|
||||
assert value_kwargs['choices'] == value_arg.possible_values
|
||||
assert value_kwargs['required'] == value_arg.is_required
|
||||
assert value_kwargs['deprecated'] == value_arg.is_deprecated
|
||||
|
||||
assert bool_arg_call is not None, "bool_arg was not registered"
|
||||
_, bool_kwargs = bool_arg_call
|
||||
assert bool_kwargs['action'] == bool_arg.action
|
||||
assert bool_kwargs['help'] == bool_arg.help
|
||||
assert bool_kwargs['deprecated'] == bool_arg.is_deprecated
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info > (3, 12), reason="for more latest python version has been other test")
|
||||
def test_argparser_register_args_py312(
|
||||
def test_argparser_registers_arguments_without_deprecated_flag_py312(
|
||||
mocker: MockerFixture, value_arg: ValueArgument, bool_arg: BooleanArgument
|
||||
) -> None:
|
||||
mock_add_argument: MockType = mocker.patch("argparse.ArgumentParser.add_argument")
|
||||
|
||||
parser: ArgParser = ArgParser(processed_args=[value_arg, bool_arg])
|
||||
_parser: ArgParser = ArgParser(processed_args=[value_arg, bool_arg])
|
||||
|
||||
expected_calls: list[call] = [
|
||||
call(
|
||||
value_arg.string_entity,
|
||||
action=value_arg.action,
|
||||
help=value_arg.help,
|
||||
default=value_arg.default,
|
||||
choices=value_arg.possible_values,
|
||||
required=value_arg.is_required,
|
||||
),
|
||||
call(
|
||||
bool_arg.string_entity,
|
||||
action=bool_arg.action,
|
||||
help=bool_arg.help,
|
||||
),
|
||||
]
|
||||
mock_add_argument.assert_has_calls(expected_calls, any_order=True)
|
||||
# ArgParser may add additional arguments (like help), so check at least 2
|
||||
assert mock_add_argument.call_count >= 2
|
||||
|
||||
# Check that value_arg was registered correctly
|
||||
value_arg_call = None
|
||||
bool_arg_call = None
|
||||
|
||||
for call_args in mock_add_argument.call_args_list:
|
||||
args, kwargs = call_args
|
||||
if len(args) > 0 and args[0] == value_arg.string_entity:
|
||||
value_arg_call = (args, kwargs)
|
||||
elif len(args) > 0 and args[0] == bool_arg.string_entity:
|
||||
bool_arg_call = (args, kwargs)
|
||||
|
||||
assert value_arg_call is not None, "value_arg was not registered"
|
||||
_, value_kwargs = value_arg_call
|
||||
assert value_kwargs['action'] == value_arg.action
|
||||
assert value_kwargs['help'] == value_arg.help
|
||||
assert value_kwargs['default'] == value_arg.default
|
||||
assert value_kwargs['choices'] == value_arg.possible_values
|
||||
assert value_kwargs['required'] == value_arg.is_required
|
||||
assert 'deprecated' not in value_kwargs
|
||||
|
||||
assert bool_arg_call is not None, "bool_arg was not registered"
|
||||
_, bool_kwargs = bool_arg_call
|
||||
assert bool_kwargs['action'] == bool_arg.action
|
||||
assert bool_kwargs['help'] == bool_arg.help
|
||||
assert 'deprecated' not in bool_kwargs
|
||||
|
||||
|
||||
def test_argparser_parse_args_populates_argspace(
|
||||
# ============================================================================
|
||||
# Tests for ArgParser argument parsing
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_argparser_parse_args_populates_argspace_correctly(
|
||||
mocker: MockerFixture, processed_args: list[ValueArgument | BooleanArgument]
|
||||
) -> None:
|
||||
mock_namespace: Namespace = Namespace(config='config.json', debug=True)
|
||||
@@ -245,11 +313,3 @@ def test_argparser_parse_args_populates_argspace(
|
||||
assert debug_arg is not None
|
||||
assert debug_arg.value is True
|
||||
assert debug_arg.founder_class is BooleanArgument
|
||||
|
||||
def test_str_input_argument():
|
||||
arg = InputArgument('host', value='192.168.0.0', founder_class=ValueArgument)
|
||||
assert str(arg) == 'InputArgument(host=192.168.0.0)'
|
||||
|
||||
def test_repr_input_argument():
|
||||
arg = InputArgument('host', value='192.168.0.0', founder_class=ValueArgument)
|
||||
assert repr(arg) == "InputArgument<name=host, value=192.168.0.0, founder_class=ValueArgument>"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from pyfakefs.fake_filesystem import FakeFilesystem
|
||||
from pytest_mock import MockerFixture
|
||||
from pytest_mock.plugin import MockType
|
||||
|
||||
from argenta.app.autocompleter.entity import (
|
||||
AutoCompleter,
|
||||
@@ -12,8 +12,17 @@ from argenta.app.autocompleter.entity import (
|
||||
)
|
||||
|
||||
|
||||
HISTORY_FILE: str = "test_history.txt"
|
||||
COMMANDS: list[str] = ["start", "stop", "status"]
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Fixtures
|
||||
# ============================================================================
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_readline(mocker: MockerFixture) -> MockType:
|
||||
def mock_readline(mocker: MockerFixture) -> Any:
|
||||
_history: list[str] = []
|
||||
|
||||
def add_history(item: str) -> None:
|
||||
@@ -30,31 +39,37 @@ def mock_readline(mocker: MockerFixture) -> MockType:
|
||||
def clear_history() -> None:
|
||||
_history.clear()
|
||||
|
||||
mock: MockType = mocker.MagicMock()
|
||||
mocker.patch('argenta.app.autocompleter.entity.readline', mock)
|
||||
mock: Any = mocker.MagicMock() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
|
||||
mocker.patch('argenta.app.autocompleter.entity.readline', mock) # pyright: ignore[reportUnknownArgumentType]
|
||||
|
||||
mock.reset_mock()
|
||||
mock.reset_mock() # pyright: ignore[reportUnknownMemberType]
|
||||
clear_history()
|
||||
|
||||
mock.add_history.side_effect = add_history
|
||||
mock.get_history_item.side_effect = get_history_item
|
||||
mock.get_current_history_length.side_effect = get_current_history_length
|
||||
mock.get_completer_delims.return_value = " "
|
||||
mock.add_history.side_effect = add_history # pyright: ignore[reportUnknownMemberType]
|
||||
mock.get_history_item.side_effect = get_history_item # pyright: ignore[reportUnknownMemberType]
|
||||
mock.get_current_history_length.side_effect = get_current_history_length # pyright: ignore[reportUnknownMemberType]
|
||||
mock.get_completer_delims.return_value = " " # pyright: ignore[reportUnknownMemberType]
|
||||
|
||||
return mock
|
||||
return mock # pyright: ignore[reportReturnType, reportUnknownVariableType]
|
||||
|
||||
|
||||
HISTORY_FILE: str = "test_history.txt"
|
||||
COMMANDS: list[str] = ["start", "stop", "status"]
|
||||
# ============================================================================
|
||||
# Tests for AutoCompleter initialization
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_initialization() -> None:
|
||||
def test_autocompleter_initializes_with_history_file_and_button() -> None:
|
||||
completer: AutoCompleter = AutoCompleter(history_filename=HISTORY_FILE, autocomplete_button="tab")
|
||||
assert completer.history_filename == HISTORY_FILE
|
||||
assert completer.autocomplete_button == "tab"
|
||||
|
||||
|
||||
def test_initial_setup_if_history_file_does_not_exist(fs: FakeFilesystem, mock_readline: MockType) -> None:
|
||||
# ============================================================================
|
||||
# Tests for initial setup
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_initial_setup_creates_history_when_file_does_not_exist(fs: FakeFilesystem, mock_readline: Any) -> None:
|
||||
if os.path.exists(HISTORY_FILE):
|
||||
os.remove(HISTORY_FILE)
|
||||
|
||||
@@ -68,8 +83,8 @@ def test_initial_setup_if_history_file_does_not_exist(fs: FakeFilesystem, mock_r
|
||||
mock_readline.parse_and_bind.assert_called_with("tab: complete")
|
||||
|
||||
|
||||
def test_initial_setup_if_history_file_exists(fs: FakeFilesystem, mock_readline: MockType) -> None:
|
||||
fs.create_file(HISTORY_FILE, contents="previous_command\n")
|
||||
def test_initial_setup_reads_existing_history_file(fs: FakeFilesystem, mock_readline: Any) -> None:
|
||||
fs.create_file(HISTORY_FILE, contents="previous_command\n") # pyright: ignore[reportUnknownMemberType]
|
||||
|
||||
completer: AutoCompleter = AutoCompleter(history_filename=HISTORY_FILE)
|
||||
completer.initial_setup(COMMANDS)
|
||||
@@ -80,7 +95,7 @@ def test_initial_setup_if_history_file_exists(fs: FakeFilesystem, mock_readline:
|
||||
mock_readline.parse_and_bind.assert_called_once()
|
||||
|
||||
|
||||
def test_initial_setup_with_no_history_filename(mock_readline: MockType) -> None:
|
||||
def test_initial_setup_works_without_history_filename(mock_readline: Any) -> None:
|
||||
completer: AutoCompleter = AutoCompleter(history_filename=None)
|
||||
completer.initial_setup(COMMANDS)
|
||||
|
||||
@@ -88,7 +103,12 @@ def test_initial_setup_with_no_history_filename(mock_readline: MockType) -> None
|
||||
assert mock_readline.add_history.call_count == len(COMMANDS)
|
||||
|
||||
|
||||
def test_exit_setup_writes_and_filters_history(fs: FakeFilesystem, mock_readline: MockType) -> None:
|
||||
# ============================================================================
|
||||
# Tests for exit setup and history filtering
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_exit_setup_writes_and_filters_duplicate_commands(fs: FakeFilesystem, mock_readline: Any) -> None:
|
||||
mock_readline.add_history.side_effect = None
|
||||
mock_readline.add_history("start server")
|
||||
mock_readline.add_history("stop client")
|
||||
@@ -96,7 +116,7 @@ def test_exit_setup_writes_and_filters_history(fs: FakeFilesystem, mock_readline
|
||||
mock_readline.add_history("start server")
|
||||
|
||||
raw_history_content: str = "\n".join(["start server", "stop client", "invalid command", "start server"])
|
||||
fs.create_file(HISTORY_FILE, contents=raw_history_content)
|
||||
fs.create_file(HISTORY_FILE, contents=raw_history_content) # pyright: ignore[reportUnknownMemberType]
|
||||
|
||||
completer: AutoCompleter = AutoCompleter(history_filename=HISTORY_FILE)
|
||||
completer.exit_setup(all_commands=["start", "stop"], ignore_command_register=False)
|
||||
@@ -109,13 +129,18 @@ def test_exit_setup_writes_and_filters_history(fs: FakeFilesystem, mock_readline
|
||||
assert lines == ["start server", "stop client"]
|
||||
|
||||
|
||||
def test_exit_setup_with_no_history_filename(mock_readline: MockType) -> None:
|
||||
def test_exit_setup_skips_writing_when_no_history_filename(mock_readline: Any) -> None:
|
||||
completer: AutoCompleter = AutoCompleter(history_filename=None)
|
||||
completer.exit_setup(all_commands=COMMANDS, ignore_command_register=False)
|
||||
mock_readline.write_history_file.assert_not_called()
|
||||
|
||||
|
||||
def test_complete_with_no_matches(mock_readline: MockType) -> None:
|
||||
# ============================================================================
|
||||
# Tests for autocomplete functionality
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_complete_returns_none_when_no_matches_found(mock_readline: Any) -> None:
|
||||
cmd: str
|
||||
for cmd in ["start", "stop"]:
|
||||
mock_readline.add_history(cmd)
|
||||
@@ -125,7 +150,7 @@ def test_complete_with_no_matches(mock_readline: MockType) -> None:
|
||||
assert completer._complete("run", 1) is None
|
||||
|
||||
|
||||
def test_complete_with_one_match(mock_readline: MockType) -> None:
|
||||
def test_complete_returns_single_match(mock_readline: Any) -> None:
|
||||
mock_readline.add_history("start server")
|
||||
mock_readline.add_history("stop server")
|
||||
|
||||
@@ -134,7 +159,7 @@ def test_complete_with_one_match(mock_readline: MockType) -> None:
|
||||
assert completer._complete("start", 1) is None
|
||||
|
||||
|
||||
def test_complete_with_multiple_matches(mock_readline: MockType) -> None:
|
||||
def test_complete_inserts_common_prefix_for_multiple_matches(mock_readline: Any) -> None:
|
||||
mock_readline.add_history("status client")
|
||||
mock_readline.add_history("status server")
|
||||
mock_readline.add_history("stop")
|
||||
@@ -152,21 +177,32 @@ def test_complete_with_multiple_matches(mock_readline: MockType) -> None:
|
||||
mock_readline.insert_text.assert_not_called()
|
||||
|
||||
|
||||
def test_is_command_exist() -> None:
|
||||
# ============================================================================
|
||||
# Tests for helper functions
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_is_command_exist_checks_case_sensitive_when_enabled() -> None:
|
||||
existing: list[str] = ["start", "stop", "status"]
|
||||
|
||||
assert _is_command_exist("start", existing, ignore_command_register=False) is True
|
||||
assert _is_command_exist("START", existing, ignore_command_register=False) is False
|
||||
assert _is_command_exist("unknown", existing, ignore_command_register=False) is False
|
||||
|
||||
|
||||
def test_is_command_exist_checks_case_insensitive_when_enabled() -> None:
|
||||
existing: list[str] = ["start", "stop", "status"]
|
||||
|
||||
assert _is_command_exist("start", existing, ignore_command_register=True) is True
|
||||
assert _is_command_exist("START", existing, ignore_command_register=True) is True
|
||||
assert _is_command_exist("unknown", existing, ignore_command_register=True) is False
|
||||
|
||||
|
||||
def test_get_history_items(mock_readline: MockType) -> None:
|
||||
def test_get_history_items_returns_empty_list_initially(mock_readline: Any) -> None:
|
||||
assert _get_history_items() == []
|
||||
|
||||
|
||||
def test_get_history_items_returns_all_added_items(mock_readline: Any) -> None:
|
||||
mock_readline.add_history("first item")
|
||||
mock_readline.add_history("second item")
|
||||
|
||||
|
||||
@@ -2,86 +2,113 @@ import re
|
||||
|
||||
import pytest
|
||||
|
||||
from argenta.command.exceptions import (EmptyInputCommandException,
|
||||
RepeatedInputFlagsException,
|
||||
UnprocessedInputFlagException)
|
||||
from argenta.command.exceptions import (
|
||||
EmptyInputCommandException,
|
||||
RepeatedInputFlagsException,
|
||||
UnprocessedInputFlagException,
|
||||
)
|
||||
from argenta.command.flag import Flag, InputFlag
|
||||
from argenta.command.flag.flags import Flags
|
||||
from argenta.command.flag.models import PossibleValues, ValidationStatus
|
||||
from argenta.command.models import Command, InputCommand
|
||||
|
||||
|
||||
def test_parse_correct_raw_command():
|
||||
# ============================================================================
|
||||
# Tests for InputCommand parsing - successful cases
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_parse_extracts_trigger_from_command_with_flags() -> None:
|
||||
assert InputCommand.parse('ssh --host 192.168.0.3').trigger == 'ssh'
|
||||
|
||||
|
||||
def test_parse_raw_command_without_flag_name_with_value():
|
||||
with pytest.raises(UnprocessedInputFlagException):
|
||||
InputCommand.parse('ssh 192.168.0.3')
|
||||
def test_parse_returns_input_command_instance() -> None:
|
||||
cmd = InputCommand.parse('ssh --host 192.168.0.3')
|
||||
assert isinstance(cmd, InputCommand)
|
||||
|
||||
|
||||
def test_parse_raw_command_with_repeated_flag_name():
|
||||
with pytest.raises(RepeatedInputFlagsException):
|
||||
InputCommand.parse('ssh --host 192.168.0.3 --host 172.198.0.43')
|
||||
|
||||
|
||||
def test_parse_raw_command_with_triple_prefix():
|
||||
def test_parse_handles_triple_prefix_flags() -> None:
|
||||
assert InputCommand.parse(
|
||||
'ssh ---host 192.168.0.0'
|
||||
).input_flags.get_flag_by_name('host') == \
|
||||
InputFlag('host', input_value='192.168.0.0', prefix='---')
|
||||
|
||||
|
||||
def test_parse_raw_command_with_unprocessed_entity():
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for InputCommand parsing - error cases
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_parse_raises_error_for_value_without_flag_name() -> None:
|
||||
with pytest.raises(UnprocessedInputFlagException):
|
||||
InputCommand.parse('ssh 192.168.0.3')
|
||||
|
||||
|
||||
def test_parse_raises_error_for_repeated_flag_names() -> None:
|
||||
with pytest.raises(RepeatedInputFlagsException):
|
||||
InputCommand.parse('ssh --host 192.168.0.3 --host 172.198.0.43')
|
||||
|
||||
|
||||
def test_parse_raises_error_for_unprocessed_entity_after_flags() -> None:
|
||||
with pytest.raises(UnprocessedInputFlagException):
|
||||
InputCommand.parse('ssh --host 192.168.0.3 9977')
|
||||
|
||||
|
||||
def test_parse_empty_raw_command():
|
||||
def test_parse_raises_error_for_empty_command() -> None:
|
||||
with pytest.raises(EmptyInputCommandException):
|
||||
InputCommand.parse('')
|
||||
|
||||
|
||||
def test_validate_invalid_input_flag1():
|
||||
command = Command('some', flags=Flag('test'))
|
||||
assert command.validate_input_flag(InputFlag('test', input_value='', status=None)) == ValidationStatus.INVALID
|
||||
# ============================================================================
|
||||
# Tests for flag validation - valid flags
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_validate_valid_input_flag2():
|
||||
def test_validate_input_flag_returns_valid_for_registered_flag() -> None:
|
||||
command = Command('some', flags=Flags([Flag('test'), Flag('more')]))
|
||||
assert command.validate_input_flag(InputFlag('more', input_value='random-value', status=None)) == ValidationStatus.VALID
|
||||
|
||||
|
||||
def test_validate_undefined_input_flag1():
|
||||
# ============================================================================
|
||||
# Tests for flag validation - invalid flags
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_validate_input_flag_returns_invalid_for_flag_with_empty_value() -> None:
|
||||
command = Command('some', flags=Flag('test'))
|
||||
assert command.validate_input_flag(InputFlag('more', input_value='', status=None)) == ValidationStatus.UNDEFINED
|
||||
assert command.validate_input_flag(InputFlag('test', input_value='', status=None)) == ValidationStatus.INVALID
|
||||
|
||||
|
||||
def test_validate_undefined_input_flag2():
|
||||
command = Command('some', flags=Flags([Flag('test'), Flag('more')]))
|
||||
assert command.validate_input_flag(InputFlag('case', input_value='', status=None)) == ValidationStatus.UNDEFINED
|
||||
|
||||
|
||||
def test_validate_undefined_input_flag3():
|
||||
command = Command('some')
|
||||
assert command.validate_input_flag(InputFlag('case', input_value='', status=None)) == ValidationStatus.UNDEFINED
|
||||
|
||||
|
||||
def test_invalid_input_flag1():
|
||||
def test_validate_input_flag_returns_invalid_when_value_provided_for_neither_flag() -> None:
|
||||
command = Command('some', flags=Flag('test', possible_values=PossibleValues.NEITHER))
|
||||
assert command.validate_input_flag(InputFlag('test', input_value='example', status=None)) == ValidationStatus.INVALID
|
||||
|
||||
|
||||
def test_invalid_input_flag2():
|
||||
def test_validate_input_flag_returns_invalid_when_value_not_in_allowed_list() -> None:
|
||||
command = Command('some', flags=Flag('test', possible_values=['some', 'case']))
|
||||
assert command.validate_input_flag(InputFlag('test', input_value='slay', status=None)) == ValidationStatus.INVALID
|
||||
|
||||
|
||||
def test_invalid_input_flag3():
|
||||
command = Command('some', flags=Flag('test', possible_values=re.compile(r'^ex\d{, 2}op$')))
|
||||
def test_validate_input_flag_returns_invalid_when_value_does_not_match_regex() -> None:
|
||||
command = Command('some', flags=Flag('test', possible_values=re.compile(r'^ex\d{1,2}op$')))
|
||||
assert command.validate_input_flag(InputFlag('test', input_value='example', status=None)) == ValidationStatus.INVALID
|
||||
|
||||
|
||||
def test_isinstance_parse_correct_raw_command():
|
||||
cmd = InputCommand.parse('ssh --host 192.168.0.3')
|
||||
assert isinstance(cmd, InputCommand)
|
||||
# ============================================================================
|
||||
# Tests for flag validation - undefined flags
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_validate_input_flag_returns_undefined_for_unregistered_flag_name() -> None:
|
||||
command = Command('some', flags=Flag('test'))
|
||||
assert command.validate_input_flag(InputFlag('more', input_value='', status=None)) == ValidationStatus.UNDEFINED
|
||||
|
||||
|
||||
def test_validate_input_flag_returns_undefined_for_unregistered_flag_in_multiple_flags() -> None:
|
||||
command = Command('some', flags=Flags([Flag('test'), Flag('more')]))
|
||||
assert command.validate_input_flag(InputFlag('case', input_value='', status=None)) == ValidationStatus.UNDEFINED
|
||||
|
||||
|
||||
def test_validate_input_flag_returns_undefined_when_command_has_no_flags() -> None:
|
||||
command = Command('some')
|
||||
assert command.validate_input_flag(InputFlag('case', input_value='', status=None)) == ValidationStatus.UNDEFINED
|
||||
|
||||
+66
-27
@@ -1,81 +1,120 @@
|
||||
from typing import Generator
|
||||
|
||||
import pytest
|
||||
from dishka import Container, make_container
|
||||
|
||||
from argenta import App, DataBridge, Router
|
||||
from argenta.di.integration import (
|
||||
FromDishka,
|
||||
_auto_inject_handlers,
|
||||
_get_container_from_response,
|
||||
setup_dishka,
|
||||
)
|
||||
from argenta.di.providers import SystemProvider
|
||||
from argenta.orchestrator.argparser import ArgParser, ArgSpace
|
||||
from argenta.response import ResponseStatus
|
||||
from dishka import Container, make_container
|
||||
import pytest
|
||||
from argenta.response.entity import Response
|
||||
from argenta.di.integration import FromDishka, _get_container_from_response, setup_dishka, _auto_inject_handlers
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Fixtures
|
||||
# ============================================================================
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def argparser() -> ArgParser:
|
||||
return ArgParser(processed_args=[])
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def container(argparser: ArgParser) -> Generator[Container]:
|
||||
def container(argparser: ArgParser) -> Generator[Container, None, None]:
|
||||
container = make_container(SystemProvider(), context={ArgParser: argparser})
|
||||
yield container
|
||||
container.close()
|
||||
|
||||
|
||||
def test_get_container_from_response(container: Container):
|
||||
# ============================================================================
|
||||
# Tests for container retrieval from response
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_get_container_from_response_extracts_container_from_first_response_arg(container: Container) -> None:
|
||||
Response.patch_by_container(container)
|
||||
response = Response(ResponseStatus.ALL_FLAGS_VALID)
|
||||
assert _get_container_from_response((response,), {}) == container
|
||||
|
||||
def test_get_container_from_response4(container: Container):
|
||||
|
||||
|
||||
def test_get_container_from_response_extracts_container_from_second_response_arg(container: Container) -> None:
|
||||
Response.patch_by_container(container)
|
||||
response = Response(ResponseStatus.ALL_FLAGS_VALID)
|
||||
assert _get_container_from_response((object(), response,), {}) == container
|
||||
|
||||
def test_get_container_from_response2(container: Container):
|
||||
|
||||
|
||||
def test_get_container_from_response_raises_error_when_container_not_patched() -> None:
|
||||
delattr(Response, '__dishka_container__')
|
||||
response = Response(ResponseStatus.ALL_FLAGS_VALID)
|
||||
with pytest.raises(RuntimeError):
|
||||
_get_container_from_response((response,), {})
|
||||
|
||||
def test_get_container_from_response3(container: Container):
|
||||
|
||||
|
||||
def test_get_container_from_response_raises_error_when_no_response_in_args(container: Container) -> None:
|
||||
Response.patch_by_container(container)
|
||||
with pytest.raises(RuntimeError):
|
||||
assert _get_container_from_response((), {}) == container
|
||||
|
||||
def test_setup_dishka(container: Container):
|
||||
_get_container_from_response((), {})
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for dishka setup
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_setup_dishka_with_auto_inject_enabled(container: Container) -> None:
|
||||
app = App()
|
||||
router = Router()
|
||||
|
||||
@router.command('command')
|
||||
def handler(res: Response, data_bridge: FromDishka[DataBridge]):
|
||||
def handler(_res: Response, data_bridge: FromDishka[DataBridge]) -> None:
|
||||
print(data_bridge)
|
||||
|
||||
app.include_router(router)
|
||||
|
||||
assert setup_dishka(app, container, auto_inject=True) is None
|
||||
|
||||
def test_setup_dishka2(container: Container):
|
||||
|
||||
|
||||
def test_setup_dishka_with_auto_inject_disabled(container: Container) -> None:
|
||||
app = App()
|
||||
assert setup_dishka(app, container, auto_inject=False) is None
|
||||
|
||||
def test_auto_inject_handlers(container: Container):
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for auto injection
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_auto_inject_handlers_injects_dependencies_into_handlers(container: Container) -> None:
|
||||
Response.patch_by_container(container)
|
||||
|
||||
app = App()
|
||||
router = Router()
|
||||
|
||||
@router.command('command')
|
||||
def handler(res: Response, data_bridge: FromDishka[DataBridge]):
|
||||
def handler(_res: Response, data_bridge: FromDishka[DataBridge]) -> None:
|
||||
print(data_bridge)
|
||||
|
||||
app.include_router(router)
|
||||
|
||||
_auto_inject_handlers(app)
|
||||
_auto_inject_handlers(app) # check idempotency
|
||||
|
||||
def test_get_from_container(container: Container):
|
||||
_auto_inject_handlers(app) # check idempotency
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for container dependency resolution
|
||||
# ============================================================================F
|
||||
|
||||
|
||||
def test_container_resolves_argspace_dependency(container: Container) -> None:
|
||||
assert isinstance(container.get(ArgSpace), ArgSpace)
|
||||
|
||||
def test_get_from_container2(container: Container):
|
||||
|
||||
|
||||
def test_container_resolves_databridge_dependency(container: Container) -> None:
|
||||
assert isinstance(container.get(DataBridge), DataBridge)
|
||||
|
||||
|
||||
@@ -1,36 +1,61 @@
|
||||
from argenta.app.dividing_line import DynamicDividingLine, StaticDividingLine
|
||||
|
||||
|
||||
def test_get_static_dividing_line_full_line():
|
||||
# ============================================================================
|
||||
# Tests for StaticDividingLine - full line generation
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_static_dividing_line_generates_default_length_with_override() -> None:
|
||||
line = StaticDividingLine('-')
|
||||
assert line.get_full_static_line(is_override=True).count('-') == 25
|
||||
|
||||
def test_get_static_dividing_line2_full_line():
|
||||
|
||||
|
||||
def test_static_dividing_line_generates_custom_length_with_formatting() -> None:
|
||||
line = StaticDividingLine('-', length=5)
|
||||
assert line.get_full_static_line(is_override=False) == '\n[dim]-----[/dim]\n'
|
||||
|
||||
def test_get_dividing_line_unit_part():
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for StaticDividingLine - unit part extraction
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_static_dividing_line_returns_space_for_empty_unit() -> None:
|
||||
line = StaticDividingLine('')
|
||||
assert line.get_unit_part() == ' '
|
||||
|
||||
def test_get_dividing_line2_unit_part():
|
||||
|
||||
def test_static_dividing_line_returns_first_character_as_unit() -> None:
|
||||
line = StaticDividingLine('+-0987654321!@#$%^&*()_')
|
||||
assert line.get_unit_part() == '+'
|
||||
|
||||
def test_get_dynamic_dividing_line_full_line():
|
||||
|
||||
# ============================================================================
|
||||
# Tests for DynamicDividingLine - full line generation
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_dynamic_dividing_line_generates_line_with_specified_length_and_override() -> None:
|
||||
line = DynamicDividingLine()
|
||||
assert line.get_full_dynamic_line(length=20, is_override=True).count('-') == 20
|
||||
|
||||
def test_get_dynamic_dividing_line2_full_line():
|
||||
|
||||
|
||||
def test_dynamic_dividing_line_generates_line_with_specified_length_and_formatting() -> None:
|
||||
line = DynamicDividingLine()
|
||||
assert line.get_full_dynamic_line(length=5, is_override=False) == '\n[dim]-----[/dim]\n'
|
||||
|
||||
def test_get_dynamic_dividing_line_unit_part():
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for DynamicDividingLine - unit part extraction
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_dynamic_dividing_line_returns_space_for_empty_unit() -> None:
|
||||
line = DynamicDividingLine('')
|
||||
assert line.get_unit_part() == ' '
|
||||
|
||||
def test_get_dynamic_dividing_line2_unit_part():
|
||||
|
||||
def test_dynamic_dividing_line_returns_first_character_as_unit() -> None:
|
||||
line = DynamicDividingLine('45n352834528&^%@&*T$G')
|
||||
assert line.get_unit_part() == '4'
|
||||
|
||||
|
||||
|
||||
+208
-120
@@ -1,100 +1,226 @@
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
from argenta.command.flag import Flag, InputFlag, PossibleValues
|
||||
from argenta.command.flag.flags import Flags, InputFlags
|
||||
import pytest
|
||||
|
||||
|
||||
def test_get_string_entity():
|
||||
# ============================================================================
|
||||
# Tests for Flag - basic properties
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_flag_string_entity_with_default_prefix() -> None:
|
||||
assert Flag(name='test').string_entity == '--test'
|
||||
|
||||
|
||||
def test_get_string_entity2():
|
||||
def test_flag_string_entity_with_custom_prefix() -> None:
|
||||
assert Flag(name='test', prefix='---').string_entity == '---test'
|
||||
|
||||
|
||||
def test_get_flag_name():
|
||||
def test_flag_name_property() -> None:
|
||||
assert Flag(name='test').name == 'test'
|
||||
|
||||
|
||||
def test_get_flag_prefix():
|
||||
def test_flag_prefix_property_default() -> None:
|
||||
assert Flag(name='test').prefix == '--'
|
||||
|
||||
|
||||
def test_get_flag_prefix2():
|
||||
def test_flag_prefix_property_custom() -> None:
|
||||
assert Flag(name='test', prefix='--').prefix == '--'
|
||||
|
||||
|
||||
def test_get_flag_value_without_set():
|
||||
assert InputFlag(name='test', input_value='', status=None).input_value == ''
|
||||
# ============================================================================
|
||||
# Tests for Flag - string representations
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_get_flag_value_with_set():
|
||||
flag = InputFlag(name='test', input_value='example', status=None)
|
||||
assert flag.input_value == 'example'
|
||||
def test_flag_str_representation() -> None:
|
||||
flag = Flag('two')
|
||||
assert str(flag) == '--two'
|
||||
|
||||
|
||||
def test_validate_incorrect_flag_value_with_list_of_possible_flag_values():
|
||||
flag = Flag(name='test', possible_values=['1', '2', '3'])
|
||||
assert flag.validate_input_flag_value('bad value') is False
|
||||
def test_flag_repr_representation() -> None:
|
||||
flag = Flag('two')
|
||||
assert repr(flag) == 'Flag<name=two, prefix=-->'
|
||||
|
||||
|
||||
def test_validate_correct_flag_value_with_list_of_possible_flag_values():
|
||||
def test_flag_equality_with_non_flag_raises_error() -> None:
|
||||
flag = Flag('two')
|
||||
not_flag = object()
|
||||
with pytest.raises(NotImplementedError):
|
||||
flag == not_flag # pyright: ignore[reportUnusedExpression]
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for Flag - value validation with list of possible values
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_flag_validates_value_in_allowed_list() -> None:
|
||||
flag = Flag(name='test', possible_values=['1', '2', '3'])
|
||||
assert flag.validate_input_flag_value('1') is True
|
||||
|
||||
|
||||
def test_validate_incorrect_flag_value_with_pattern_of_possible_flag_values():
|
||||
flag = Flag(name='test', possible_values=re.compile(r'192.168.\d+.\d+'))
|
||||
assert flag.validate_input_flag_value('152.123.9.8') is False
|
||||
def test_flag_rejects_value_not_in_allowed_list() -> None:
|
||||
flag = Flag(name='test', possible_values=['1', '2', '3'])
|
||||
assert flag.validate_input_flag_value('bad value') is False
|
||||
|
||||
|
||||
def test_validate_correct_flag_value_with_pattern_of_possible_flag_values():
|
||||
# ============================================================================
|
||||
# Tests for Flag - value validation with regex pattern
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_flag_validates_value_matching_regex_pattern() -> None:
|
||||
flag = Flag(name='test', possible_values=re.compile(r'192.168.\d+.\d+'))
|
||||
assert flag.validate_input_flag_value('192.168.9.8') is True
|
||||
|
||||
|
||||
def test_validate_correct_empty_flag_value_without_possible_flag_values():
|
||||
def test_flag_rejects_value_not_matching_regex_pattern() -> None:
|
||||
flag = Flag(name='test', possible_values=re.compile(r'192.168.\d+.\d+'))
|
||||
assert flag.validate_input_flag_value('152.123.9.8') is False
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for Flag - value validation with NEITHER and ALL
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_flag_validates_empty_value_when_neither_allowed() -> None:
|
||||
flag = Flag(name='test', possible_values=PossibleValues.NEITHER)
|
||||
assert flag.validate_input_flag_value('') is True
|
||||
|
||||
|
||||
def test_validate_correct_empty_flag_value_with_possible_flag_values():
|
||||
flag = Flag(name='test', possible_values=PossibleValues.NEITHER)
|
||||
assert flag.validate_input_flag_value('') is True
|
||||
|
||||
|
||||
def test_validate_incorrect_random_flag_value_without_possible_flag_values():
|
||||
def test_flag_rejects_non_empty_value_when_neither_allowed() -> None:
|
||||
flag = Flag(name='test', possible_values=PossibleValues.NEITHER)
|
||||
assert flag.validate_input_flag_value('random value') is False
|
||||
|
||||
|
||||
def test_validate_correct_random_flag_value_with_possible_flag_values():
|
||||
def test_flag_validates_any_value_when_all_allowed() -> None:
|
||||
flag = Flag(name='test', possible_values=PossibleValues.ALL)
|
||||
assert flag.validate_input_flag_value('random value') is True
|
||||
|
||||
|
||||
def test_get_input_flag1():
|
||||
# ============================================================================
|
||||
# Tests for InputFlag - basic properties
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_input_flag_stores_empty_value() -> None:
|
||||
assert InputFlag(name='test', input_value='', status=None).input_value == ''
|
||||
|
||||
|
||||
def test_input_flag_stores_provided_value() -> None:
|
||||
flag = InputFlag(name='test', input_value='example', status=None)
|
||||
assert flag.input_value == 'example'
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for InputFlag - string representations
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_input_flag_str_representation() -> None:
|
||||
flag = InputFlag('two', input_value='value')
|
||||
assert str(flag) == '--two value'
|
||||
|
||||
|
||||
def test_input_flag_repr_representation() -> None:
|
||||
flag = InputFlag('two', input_value='some_value')
|
||||
assert repr(flag) == 'InputFlag<name=two, prefix=--, value=some_value, status=None>'
|
||||
|
||||
|
||||
def test_input_flag_equality_with_non_flag_raises_error() -> None:
|
||||
flag = InputFlag('two', input_value='')
|
||||
not_flag = object()
|
||||
with pytest.raises(NotImplementedError):
|
||||
flag == not_flag # pyright: ignore[reportUnusedExpression]
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for InputFlags collection - retrieval
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_input_flags_get_by_name_finds_single_flag() -> None:
|
||||
flag = InputFlag(name='test', input_value='', status=None)
|
||||
input_flags = InputFlags([flag])
|
||||
assert input_flags.get_flag_by_name('test') == flag
|
||||
|
||||
|
||||
def test_get_input_flag2():
|
||||
def test_input_flags_get_by_name_finds_flag_in_multiple() -> None:
|
||||
flag = InputFlag(name='test', input_value='', status=None)
|
||||
flag2 = InputFlag(name='some', input_value='', status=None)
|
||||
input_flags = InputFlags([flag, flag2])
|
||||
assert input_flags.get_flag_by_name('some') == flag2
|
||||
|
||||
|
||||
def test_get_undefined_input_flag():
|
||||
def test_input_flags_get_by_name_returns_none_for_missing_flag() -> None:
|
||||
flag = InputFlag(name='test', input_value='', status=None)
|
||||
flag2 = InputFlag(name='some', input_value='', status=None)
|
||||
input_flags = InputFlags([flag, flag2])
|
||||
assert input_flags.get_flag_by_name('case') is None
|
||||
|
||||
|
||||
def test_get_flags():
|
||||
# ============================================================================
|
||||
# Tests for InputFlags collection - equality and containment
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_input_flags_not_equal_when_different_length() -> None:
|
||||
flags = InputFlags([InputFlag('some', input_value='')])
|
||||
flags2 = InputFlags([
|
||||
InputFlag('some', input_value=''),
|
||||
InputFlag('some2', input_value='')
|
||||
])
|
||||
assert flags != flags2
|
||||
|
||||
|
||||
def test_input_flags_not_equal_to_non_input_flags() -> None:
|
||||
flags = InputFlags([InputFlag('some', input_value='')])
|
||||
not_flags = object()
|
||||
assert flags != not_flags
|
||||
|
||||
|
||||
def test_input_flags_contains_existing_flag() -> None:
|
||||
flag = InputFlag('some', input_value='')
|
||||
flags = InputFlags([flag])
|
||||
assert flag in flags
|
||||
|
||||
|
||||
def test_input_flags_does_not_contain_missing_flag() -> None:
|
||||
flags = InputFlags([InputFlag('some', input_value='')])
|
||||
flag = InputFlag('nonexists', input_value='')
|
||||
assert flag not in flags
|
||||
|
||||
|
||||
def test_input_flags_contains_raises_error_for_non_flag() -> None:
|
||||
flags = InputFlags([InputFlag('some', input_value='')])
|
||||
not_flag = object
|
||||
with pytest.raises(TypeError):
|
||||
not_flag in flags # pyright: ignore[reportUnusedExpression]
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for Flags collection - adding flags
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_flags_add_single_flag() -> None:
|
||||
flags = Flags()
|
||||
flags.add_flag(Flag('test'))
|
||||
assert len(flags.flags) == 1
|
||||
|
||||
|
||||
def test_flags_add_multiple_flags() -> None:
|
||||
flags = Flags()
|
||||
flags.add_flags([Flag('test'), Flag('test2')])
|
||||
assert len(flags.flags) == 2
|
||||
|
||||
|
||||
def test_flags_stores_added_flags() -> None:
|
||||
flags = Flags()
|
||||
list_of_flags = [
|
||||
Flag('test1'),
|
||||
@@ -105,122 +231,84 @@ def test_get_flags():
|
||||
assert flags.flags == list_of_flags
|
||||
|
||||
|
||||
def test_add_flag():
|
||||
flags = Flags()
|
||||
flags.add_flag(Flag('test'))
|
||||
assert len(flags.flags) == 1
|
||||
# ============================================================================
|
||||
# Tests for Flags collection - retrieval
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_add_flags():
|
||||
flags = Flags()
|
||||
flags.add_flags([Flag('test'), Flag('test2')])
|
||||
assert len(flags.flags) == 2
|
||||
|
||||
def test_eq_flags():
|
||||
def test_flags_get_by_name_finds_flag() -> None:
|
||||
flags = Flags([Flag('some')])
|
||||
assert flags.get_flag_by_name('some') == Flag('some')
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for Flags collection - equality and containment
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_flags_equal_when_same_flags() -> None:
|
||||
flags = Flags([Flag('some')])
|
||||
flags2 = Flags([Flag('some')])
|
||||
assert flags == flags2
|
||||
|
||||
def test_contains_flags():
|
||||
flags = Flags([Flag('some')])
|
||||
flag = Flag('some')
|
||||
assert flag in flags
|
||||
|
||||
def test_eq_flags2():
|
||||
|
||||
|
||||
def test_flags_not_equal_when_different_flags() -> None:
|
||||
flags = Flags([Flag('some')])
|
||||
flags2 = Flags([Flag('other')])
|
||||
assert flags != flags2
|
||||
|
||||
def test_eq_flags3():
|
||||
|
||||
|
||||
def test_flags_not_equal_when_different_length() -> None:
|
||||
flags = Flags([Flag('some')])
|
||||
flags2 = Flags([Flag('some'), Flag('other')])
|
||||
assert flags != flags2
|
||||
|
||||
def test_eq_flags4():
|
||||
|
||||
|
||||
def test_flags_not_equal_to_non_flags() -> None:
|
||||
flags = Flags([Flag('some')])
|
||||
not_flags = object()
|
||||
assert flags != not_flags
|
||||
|
||||
def test_contains_flags2():
|
||||
|
||||
|
||||
def test_flags_contains_existing_flag() -> None:
|
||||
flags = Flags([Flag('some')])
|
||||
flag = Flag('some')
|
||||
assert flag in flags
|
||||
|
||||
|
||||
def test_flags_does_not_contain_missing_flag() -> None:
|
||||
flags = Flags([Flag('some')])
|
||||
flag = Flag('nonexists')
|
||||
assert flag not in flags
|
||||
|
||||
def test_contains_flags3():
|
||||
|
||||
|
||||
def test_flags_contains_raises_error_for_non_flag() -> None:
|
||||
flags = Flags([Flag('some')])
|
||||
not_flag = object
|
||||
with pytest.raises(TypeError):
|
||||
not_flag in flags # pyright: ignore[reportUnusedExpression]
|
||||
|
||||
def test_get_flag_by_name():
|
||||
flags = Flags([Flag('some')])
|
||||
assert flags.get_flag_by_name('some') == Flag('some')
|
||||
|
||||
def test_eq_input_flags3():
|
||||
flags = InputFlags([InputFlag('some', input_value='')])
|
||||
flags2 = InputFlags([
|
||||
InputFlag('some', input_value=''),
|
||||
InputFlag('some2', input_value='')
|
||||
])
|
||||
assert flags != flags2
|
||||
|
||||
def test_eq_input_flags4():
|
||||
flags = InputFlags([InputFlag('some', input_value='')])
|
||||
not_flags = object()
|
||||
assert flags != not_flags
|
||||
|
||||
def test_contains_input_flags2():
|
||||
flags = InputFlags([InputFlag('some', input_value='')])
|
||||
flag = InputFlag('nonexists', input_value='')
|
||||
assert flag not in flags
|
||||
|
||||
def test_contains_input_flags3():
|
||||
flags = InputFlags([InputFlag('some', input_value='')])
|
||||
not_flag = object
|
||||
with pytest.raises(TypeError):
|
||||
not_flag in flags # pyright: ignore[reportUnusedExpression]
|
||||
|
||||
def test_len_flags():
|
||||
|
||||
# ============================================================================
|
||||
# Tests for Flags collection - special methods
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_flags_len_returns_count() -> None:
|
||||
flags = Flags([Flag('one'), Flag('two')])
|
||||
assert len(flags) == 2
|
||||
|
||||
def test_bool_flags():
|
||||
|
||||
|
||||
def test_flags_bool_returns_true_when_not_empty() -> None:
|
||||
flags = Flags([Flag('one'), Flag('two')])
|
||||
assert bool(flags)
|
||||
|
||||
def test_bool_flags2():
|
||||
|
||||
|
||||
def test_flags_bool_returns_false_when_empty() -> None:
|
||||
flags = Flags([])
|
||||
assert not bool(flags)
|
||||
|
||||
def test_getitem_flags():
|
||||
|
||||
|
||||
def test_flags_getitem_returns_flag_at_index() -> None:
|
||||
flags = Flags([Flag('one'), Flag('two')])
|
||||
assert flags[1] == Flag('two')
|
||||
|
||||
def test_str_flag():
|
||||
flag = Flag('two')
|
||||
assert str(flag) == '--two'
|
||||
|
||||
def test_repr_flag():
|
||||
flag = Flag('two')
|
||||
assert repr(flag) == 'Flag<name=two, prefix=-->'
|
||||
|
||||
def test_eq_flag():
|
||||
flag = Flag('two')
|
||||
not_flag = object()
|
||||
with pytest.raises(NotImplementedError):
|
||||
flag == not_flag # pyright: ignore[reportUnusedExpression]
|
||||
|
||||
def test_str_input_flag():
|
||||
flag = InputFlag('two', input_value='value')
|
||||
assert str(flag) == '--two value'
|
||||
|
||||
def test_repr_input_flag():
|
||||
flag = InputFlag('two', input_value='some_value')
|
||||
assert repr(flag) == 'InputFlag<name=two, prefix=--, value=some_value, status=None>'
|
||||
|
||||
def test_eq_input_flag():
|
||||
flag = InputFlag('two', input_value='')
|
||||
not_flag = object()
|
||||
with pytest.raises(NotImplementedError):
|
||||
flag == not_flag # pyright: ignore[reportUnusedExpression]
|
||||
|
||||
@@ -2,27 +2,37 @@ from datetime import date, datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from argenta.data_bridge import DataBridge
|
||||
from argenta.command.flag.models import InputFlag
|
||||
from argenta.command.flag.flags.models import InputFlags
|
||||
from argenta.command.flag.models import InputFlag
|
||||
from argenta.data_bridge import DataBridge
|
||||
from argenta.response.entity import EMPTY_INPUT_FLAGS, Response
|
||||
from argenta.response.status import ResponseStatus
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Fixtures
|
||||
# ============================================================================
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def data_bridge():
|
||||
def data_bridge() -> DataBridge:
|
||||
"""Create a new DataBridge instance for each test"""
|
||||
return DataBridge()
|
||||
|
||||
|
||||
def test_update_data_basic(data_bridge: DataBridge):
|
||||
# ============================================================================
|
||||
# Tests for DataBridge - basic data operations
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_databridge_update_stores_basic_data(data_bridge: DataBridge) -> None:
|
||||
"""Test basic data update functionality"""
|
||||
test_data = {"key1": "value1", "key2": "value2"}
|
||||
data_bridge.update(test_data)
|
||||
assert data_bridge.get_all() == test_data
|
||||
|
||||
|
||||
def test_update_data_with_datetime(data_bridge: DataBridge):
|
||||
def test_databridge_update_stores_datetime_objects(data_bridge: DataBridge) -> None:
|
||||
"""Test updating data with datetime objects"""
|
||||
test_datetime = datetime(2024, 1, 15, 10, 30, 45)
|
||||
test_data = {"created_at": test_datetime, "name": "test"}
|
||||
@@ -33,7 +43,7 @@ def test_update_data_with_datetime(data_bridge: DataBridge):
|
||||
assert result["name"] == "test"
|
||||
|
||||
|
||||
def test_update_data_multiple_calls(data_bridge: DataBridge):
|
||||
def test_databridge_multiple_updates_merge_data(data_bridge: DataBridge) -> None:
|
||||
"""Test multiple update calls merge data"""
|
||||
first_data = {"key1": "value1"}
|
||||
second_data = {"key2": "value2"}
|
||||
@@ -42,12 +52,37 @@ def test_update_data_multiple_calls(data_bridge: DataBridge):
|
||||
assert len(data_bridge.get_all()) == 2
|
||||
|
||||
|
||||
def test_get_data_empty(data_bridge: DataBridge):
|
||||
# ============================================================================
|
||||
# Tests for DataBridge - data retrieval
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_databridge_get_all_returns_empty_dict_initially(data_bridge: DataBridge) -> None:
|
||||
"""Test get_all returns empty dict when no data"""
|
||||
assert data_bridge.get_all() == {}
|
||||
|
||||
|
||||
def test_clear_data(data_bridge: DataBridge):
|
||||
def test_databridge_get_by_key_retrieves_correct_values(data_bridge: DataBridge) -> None:
|
||||
"""Test get_by_key retrieves correct value"""
|
||||
test_data = {"key1": "value1", "key2": date(2024, 1, 1)}
|
||||
data_bridge.update(test_data)
|
||||
assert data_bridge.get_by_key("key1") == "value1"
|
||||
assert data_bridge.get_by_key("key2") == date(2024, 1, 1)
|
||||
|
||||
|
||||
def test_databridge_get_by_key_returns_none_for_missing_key(data_bridge: DataBridge) -> None:
|
||||
"""Test get_by_key returns None for nonexistent key"""
|
||||
test_data = {"key1": "value1"}
|
||||
data_bridge.update(test_data)
|
||||
assert data_bridge.get_by_key("nonexistent") is None
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for DataBridge - data deletion
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_databridge_clear_all_removes_all_data(data_bridge: DataBridge) -> None:
|
||||
"""Test clear_all removes all data"""
|
||||
data_bridge.update({"key": "value"})
|
||||
assert data_bridge.get_all() != {}
|
||||
@@ -55,7 +90,7 @@ def test_clear_data(data_bridge: DataBridge):
|
||||
assert data_bridge.get_all() == {}
|
||||
|
||||
|
||||
def test_delete_from_data(data_bridge: DataBridge):
|
||||
def test_databridge_delete_by_key_removes_specific_key(data_bridge: DataBridge) -> None:
|
||||
"""Test delete_by_key removes specific key"""
|
||||
test_data = {"key1": "value1", "key2": "value2"}
|
||||
data_bridge.update(test_data)
|
||||
@@ -65,29 +100,25 @@ def test_delete_from_data(data_bridge: DataBridge):
|
||||
assert "key2" in result
|
||||
|
||||
|
||||
def test_delete_from_data_nonexistent_key(data_bridge: DataBridge):
|
||||
def test_databridge_delete_by_key_raises_error_for_missing_key(data_bridge: DataBridge) -> None:
|
||||
"""Test delete_by_key with nonexistent key raises KeyError"""
|
||||
with pytest.raises(KeyError):
|
||||
data_bridge.delete_by_key("nonexistent_key")
|
||||
|
||||
|
||||
def test_get_by_key(data_bridge: DataBridge):
|
||||
"""Test get_by_key retrieves correct value"""
|
||||
test_data = {"key1": "value1", "key2": date(2024, 1, 1)}
|
||||
data_bridge.update(test_data)
|
||||
assert data_bridge.get_by_key("key1") == "value1"
|
||||
assert data_bridge.get_by_key("key2") == date(2024, 1, 1)
|
||||
assert data_bridge.get_by_key("nonexistent") is None
|
||||
# ============================================================================
|
||||
# Tests for Response - initialization
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_response_initialization_basic():
|
||||
def test_response_initializes_with_status_and_empty_flags() -> None:
|
||||
"""Test basic Response initialization"""
|
||||
response = Response(ResponseStatus.ALL_FLAGS_VALID)
|
||||
assert response.status == ResponseStatus.ALL_FLAGS_VALID
|
||||
assert response.input_flags == EMPTY_INPUT_FLAGS
|
||||
|
||||
|
||||
def test_response_initialization_with_flags():
|
||||
def test_response_initializes_with_status_and_input_flags() -> None:
|
||||
"""Test Response initialization with input flags"""
|
||||
input_flags = InputFlags([InputFlag('test', input_value='value', status=None)])
|
||||
response = Response(ResponseStatus.INVALID_VALUE_FLAGS, input_flags)
|
||||
@@ -95,7 +126,12 @@ def test_response_initialization_with_flags():
|
||||
assert response.input_flags == input_flags
|
||||
|
||||
|
||||
def test_response_status_types():
|
||||
# ============================================================================
|
||||
# Tests for Response - status types
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_response_accepts_all_status_types() -> None:
|
||||
"""Test Response with different status types"""
|
||||
statuses = [
|
||||
ResponseStatus.ALL_FLAGS_VALID,
|
||||
|
||||
+168
-108
@@ -1,4 +1,5 @@
|
||||
import re
|
||||
|
||||
import pytest
|
||||
from pytest import CaptureFixture
|
||||
|
||||
@@ -9,131 +10,48 @@ from argenta.command.flag.models import PossibleValues, ValidationStatus
|
||||
from argenta.response.entity import Response
|
||||
from argenta.router import Router
|
||||
from argenta.router.entity import _structuring_input_flags, _validate_func_args # pyright: ignore[reportPrivateUsage]
|
||||
from argenta.router.exceptions import (RepeatedFlagNameException,
|
||||
RequiredArgumentNotPassedException,
|
||||
TriggerContainSpacesException)
|
||||
from argenta.router.exceptions import (
|
||||
RepeatedFlagNameException,
|
||||
RequiredArgumentNotPassedException,
|
||||
TriggerContainSpacesException,
|
||||
)
|
||||
|
||||
|
||||
def test_register_command_with_spaces_in_trigger():
|
||||
# ============================================================================
|
||||
# Tests for command validation
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_validate_command_raises_error_for_trigger_with_spaces() -> None:
|
||||
router = Router()
|
||||
with pytest.raises(TriggerContainSpacesException):
|
||||
router._validate_command(Command(trigger='command with spaces'))
|
||||
|
||||
def test_register_command_with_repeated_flags():
|
||||
|
||||
def test_validate_command_raises_error_for_repeated_flag_names() -> None:
|
||||
router = Router()
|
||||
with pytest.raises(RepeatedFlagNameException):
|
||||
router._validate_command(Command(trigger='command', flags=Flags([Flag('test'), Flag('test')])))
|
||||
|
||||
def test_structuring_input_flags1():
|
||||
cmd = Command('cmd')
|
||||
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)])
|
||||
|
||||
def test_structuring_input_flags2():
|
||||
cmd = Command('cmd')
|
||||
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)])
|
||||
# ============================================================================
|
||||
# Tests for function argument validation
|
||||
# ============================================================================
|
||||
|
||||
def test_structuring_input_flags3():
|
||||
cmd = Command('cmd', flags=Flag('port'))
|
||||
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)])
|
||||
|
||||
def test_structuring_input_flags4():
|
||||
command = Command('cmd', flags=Flag('ssh', possible_values=PossibleValues.NEITHER))
|
||||
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)])
|
||||
|
||||
def test_structuring_input_flags5():
|
||||
command = Command('cmd', flags=Flag('ssh', possible_values=re.compile(r'some[1-5]$')))
|
||||
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)])
|
||||
|
||||
def test_structuring_input_flags6():
|
||||
command = Command('cmd', flags=Flag('ssh', possible_values=['example']))
|
||||
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)])
|
||||
|
||||
def test_structuring_input_flags7():
|
||||
command = Command('cmd', flags=Flag('port'))
|
||||
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)])
|
||||
|
||||
def test_structuring_input_flags8():
|
||||
command = Command('cmd', flags=Flag('port', possible_values=['some2', 'some3']))
|
||||
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)])
|
||||
|
||||
def test_structuring_input_flags9():
|
||||
command = Command('cmd', flags=Flag('ssh', possible_values=re.compile(r'more[1-5]$')))
|
||||
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)])
|
||||
|
||||
def test_structuring_input_flags10():
|
||||
command = Command('cmd', flags=Flag('ssh', possible_values=PossibleValues.NEITHER))
|
||||
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)])
|
||||
|
||||
def test_validate_incorrect_func_args1():
|
||||
def handler():
|
||||
def test_validate_func_args_raises_error_for_missing_response_parameter() -> None:
|
||||
def handler() -> None:
|
||||
pass
|
||||
with pytest.raises(RequiredArgumentNotPassedException):
|
||||
_validate_func_args(handler) # pyright: ignore[reportArgumentType]
|
||||
_validate_func_args(handler) # pyright: ignore[reportArgumentType]
|
||||
|
||||
def test_get_router_aliases():
|
||||
router = Router()
|
||||
@router.command(Command('some', aliases={'test', 'case'}))
|
||||
def handler(response: Response) -> None:
|
||||
|
||||
def test_validate_func_args_prints_warning_for_wrong_type_hint(capsys: CaptureFixture[str]) -> None:
|
||||
class NotResponse:
|
||||
pass
|
||||
assert router.aliases == {'test', 'case'}
|
||||
|
||||
def test_get_router_aliases2():
|
||||
router = Router()
|
||||
@router.command(Command('some', aliases={'test', 'case'}))
|
||||
def handler(response: Response):
|
||||
def func(_response: NotResponse) -> None:
|
||||
pass
|
||||
@router.command(Command('ext', aliases={'more', 'foo'}))
|
||||
def handler2(response: Response):
|
||||
pass
|
||||
assert router.aliases == {'test', 'case', 'more', 'foo'}
|
||||
|
||||
def test_get_router_aliases3():
|
||||
router = Router()
|
||||
@router.command(Command('some'))
|
||||
def handler(response: Response):
|
||||
pass
|
||||
assert router.aliases == set()
|
||||
|
||||
def test_find_appropiate_handler(capsys: pytest.CaptureFixture[str]):
|
||||
router = Router()
|
||||
|
||||
@router.command(Command('hello', aliases={'hi'}))
|
||||
def handler(res: Response):
|
||||
print("Hello World!")
|
||||
|
||||
router.finds_appropriate_handler(InputCommand('hi'))
|
||||
|
||||
output = capsys.readouterr()
|
||||
|
||||
assert "Hello World!" in output.out
|
||||
|
||||
def test_find_appropiate_handler2(capsys: CaptureFixture[str]):
|
||||
router = Router()
|
||||
|
||||
@router.command(Command('hello', flags=Flag('flag'), aliases={'hi'}))
|
||||
def handler(res: Response):
|
||||
print("Hello World!")
|
||||
|
||||
router.finds_appropriate_handler(InputCommand('hi'))
|
||||
|
||||
output = capsys.readouterr()
|
||||
|
||||
assert "Hello World!" in output.out
|
||||
|
||||
def test_wrong_typehint(capsys: pytest.CaptureFixture[str]):
|
||||
class NotResponse: pass
|
||||
|
||||
def func(response: NotResponse): pass
|
||||
|
||||
_validate_func_args(func)
|
||||
|
||||
@@ -141,8 +59,150 @@ def test_wrong_typehint(capsys: pytest.CaptureFixture[str]):
|
||||
|
||||
assert "WARNING" in output.out
|
||||
|
||||
def test_missing_typehint(capsys: pytest.CaptureFixture[str]):
|
||||
def func(response): pass # pyright: ignore[reportMissingParameterType, reportUnknownParameterType]
|
||||
|
||||
def test_validate_func_args_accepts_missing_type_hint(capsys: CaptureFixture[str]) -> None:
|
||||
def func(response) -> None: # pyright: ignore[reportMissingParameterType, reportUnknownParameterType]
|
||||
pass
|
||||
_validate_func_args(func) # pyright: ignore[reportUnknownArgumentType]
|
||||
output = capsys.readouterr()
|
||||
assert output.out == ''
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for input flag structuring - undefined flags
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_structuring_input_flags_marks_unregistered_flag_as_undefined() -> None:
|
||||
cmd = Command('cmd')
|
||||
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)])
|
||||
|
||||
|
||||
def test_structuring_input_flags_marks_unregistered_flag_with_value_as_undefined() -> None:
|
||||
cmd = Command('cmd')
|
||||
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)])
|
||||
|
||||
|
||||
def test_structuring_input_flags_marks_flag_undefined_when_different_flag_registered() -> None:
|
||||
cmd = Command('cmd', flags=Flag('port'))
|
||||
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)])
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for input flag structuring - invalid flags
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_structuring_input_flags_marks_flag_invalid_when_value_provided_for_neither() -> None:
|
||||
command = Command('cmd', flags=Flag('ssh', possible_values=PossibleValues.NEITHER))
|
||||
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)])
|
||||
|
||||
|
||||
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]$')))
|
||||
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)])
|
||||
|
||||
|
||||
def test_structuring_input_flags_marks_flag_invalid_when_value_not_in_list() -> None:
|
||||
command = Command('cmd', flags=Flag('ssh', possible_values=['example']))
|
||||
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)])
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for input flag structuring - valid flags
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_structuring_input_flags_marks_registered_flag_as_valid() -> None:
|
||||
command = Command('cmd', flags=Flag('port'))
|
||||
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)])
|
||||
|
||||
|
||||
def test_structuring_input_flags_marks_flag_valid_when_value_in_list() -> None:
|
||||
command = Command('cmd', flags=Flag('port', possible_values=['some2', 'some3']))
|
||||
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)])
|
||||
|
||||
|
||||
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]$')))
|
||||
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)])
|
||||
|
||||
|
||||
def test_structuring_input_flags_marks_flag_valid_when_empty_value_for_neither() -> None:
|
||||
command = Command('cmd', flags=Flag('ssh', possible_values=PossibleValues.NEITHER))
|
||||
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)])
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for router aliases
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_router_aliases_returns_command_aliases() -> None:
|
||||
router = Router()
|
||||
@router.command(Command('some', aliases={'test', 'case'}))
|
||||
def handler(_response: Response) -> None:
|
||||
pass
|
||||
assert router.aliases == {'test', 'case'}
|
||||
|
||||
|
||||
def test_router_aliases_returns_combined_aliases_from_multiple_commands() -> None:
|
||||
router = Router()
|
||||
@router.command(Command('some', aliases={'test', 'case'}))
|
||||
def handler(_response: Response) -> None:
|
||||
pass
|
||||
@router.command(Command('ext', aliases={'more', 'foo'}))
|
||||
def handler2(_response: Response) -> None:
|
||||
pass
|
||||
assert router.aliases == {'test', 'case', 'more', 'foo'}
|
||||
|
||||
|
||||
def test_router_aliases_returns_empty_set_when_no_aliases() -> None:
|
||||
router = Router()
|
||||
@router.command(Command('some'))
|
||||
def handler(_response: Response) -> None:
|
||||
pass
|
||||
assert router.aliases == set()
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Tests for handler finding and execution
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_finds_appropriate_handler_executes_handler_by_alias(capsys: CaptureFixture[str]) -> None:
|
||||
router = Router()
|
||||
|
||||
@router.command(Command('hello', aliases={'hi'}))
|
||||
def handler(_res: Response) -> None:
|
||||
print("Hello World!")
|
||||
|
||||
router.finds_appropriate_handler(InputCommand('hi'))
|
||||
|
||||
output = capsys.readouterr()
|
||||
|
||||
assert "Hello World!" in output.out
|
||||
|
||||
|
||||
def test_finds_appropriate_handler_executes_handler_with_flags_by_alias(capsys: CaptureFixture[str]) -> None:
|
||||
router = Router()
|
||||
|
||||
@router.command(Command('hello', flags=Flag('flag'), aliases={'hi'}))
|
||||
def handler(_res: Response) -> None:
|
||||
print("Hello World!")
|
||||
|
||||
router.finds_appropriate_handler(InputCommand('hi'))
|
||||
|
||||
output = capsys.readouterr()
|
||||
|
||||
assert "Hello World!" in output.out
|
||||
|
||||
Reference in New Issue
Block a user