"""Behave steps for TUI input mode router.""" from __future__ import annotations import os import shutil import tempfile from pathlib import Path from unittest.mock import patch from behave import given, then, when from behave.runner import Context from cleveragents.tui import app as tui_app_module from cleveragents.tui.input import reference_parser from cleveragents.tui.input.modes import InputModeRouter from cleveragents.tui.input.reference_parser import parse_references, suggestions from cleveragents.tui.input.shell_exec import looks_dangerous @when('I parse TUI references for "{line}"') def step_parse_references(context: Context, line: str) -> None: context.tui_ref_result = parse_references(line) @then('the parsed line should include "{token}"') def step_parsed_contains(context: Context, token: str) -> None: assert token in context.tui_ref_result.expanded_line @when('I route TUI input "{line}"') def step_route_input(context: Context, line: str) -> None: router = InputModeRouter(command_handler=lambda raw: f"ok:/{raw}") context.tui_mode_result = router.process(line) @then('the TUI mode should be "{mode}"') def step_mode_equals(context: Context, mode: str) -> None: assert context.tui_mode_result.mode.value == mode @then('the TUI command result should be "{value}"') def step_command_result(context: Context, value: str) -> None: assert context.tui_mode_result.command_result == value @then('the TUI shell stdout should contain "{value}"') def step_shell_stdout(context: Context, value: str) -> None: shell = context.tui_mode_result.shell_result assert shell is not None assert value in shell.stdout @then('the TUI shell stderr should contain "{value}"') def step_shell_stderr(context: Context, value: str) -> None: shell = context.tui_mode_result.shell_result assert shell is not None assert value in shell.stderr @when('I check shell danger detection for "{command}"') def step_check_shell_danger(context: Context, command: str) -> None: context.shell_danger_result = looks_dangerous(command) @then('shell danger detection result should be "{value}"') def step_shell_danger_result(context: Context, value: str) -> None: expected = value.strip().lower() == "true" assert context.shell_danger_result is expected @given("a deterministic TUI reference fixture") def step_deterministic_tui_reference_fixture(context: Context) -> None: fixture_dir = Path(tempfile.mkdtemp()) (fixture_dir / "README.md").write_text("# fixture\n", encoding="utf-8") (fixture_dir / ".git").mkdir(exist_ok=True) (fixture_dir / ".git" / "secret.txt").write_text("secret\n", encoding="utf-8") context.tui_reference_fixture_dir = fixture_dir context.add_cleanup(lambda: shutil.rmtree(str(fixture_dir), ignore_errors=True)) @when("I parse and suggest TUI references using fixture") def step_parse_and_suggest_with_fixture(context: Context) -> None: context.tui_walk_count = 0 context.tui_fixture_suggestions = [] reference_parser._catalog_cache["cwd"] = None reference_parser._catalog_cache["created_at"] = 0.0 reference_parser._catalog_cache["catalog"] = None real_walk = os.walk def counting_walk(*args: object, **kwargs: object): context.tui_walk_count += 1 return real_walk(*args, **kwargs) with ( patch( "cleveragents.tui.input.reference_parser.Path.cwd", return_value=context.tui_reference_fixture_dir, ), patch( "cleveragents.tui.input.reference_parser.os.walk", side_effect=counting_walk ), ): parse_references("inspect @README.md") context.tui_fixture_suggestions = suggestions("secret", category="resource") @then('TUI walk count should be "{count}"') def step_tui_walk_count(context: Context, count: str) -> None: assert context.tui_walk_count == int(count) @then('TUI suggestions should not include "{value}"') def step_tui_suggestions_not_include(context: Context, value: str) -> None: assert all( value not in suggestion for suggestion in context.tui_fixture_suggestions ) @when("I check TUI app textual availability flag") def step_check_tui_textual_availability(context: Context) -> None: context.tui_textual_available = tui_app_module.textual_available() @then("TUI textual availability should be boolean") def step_tui_textual_is_bool(context: Context) -> None: assert isinstance(context.tui_textual_available, bool) @when("I run fallback TUI app") def step_run_fallback_tui_app(context: Context) -> None: context.tui_fallback_error = None fallback = tui_app_module._FallbackCleverAgentsTuiApp( command_router=object(), persona_state=object() ) try: fallback.run() except RuntimeError as exc: context.tui_fallback_error = exc @then('fallback TUI app should fail with "{message}"') def step_fallback_tui_fails(context: Context, message: str) -> None: assert context.tui_fallback_error is not None assert message in str(context.tui_fallback_error) @given('a TUI prompt value "{value}"') def step_set_tui_prompt_value(context: Context, value: str) -> None: context.tui_prompt_value = value @when("I clear pending TUI reference token via escape") def step_clear_pending_reference(context: Context) -> None: cleanup = tui_app_module._strip_pending_reference_token assert callable(cleanup) context.tui_prompt_value = cleanup(context.tui_prompt_value) @then('the TUI prompt value should be "{expected}"') def step_assert_tui_prompt_value(context: Context, expected: str) -> None: assert context.tui_prompt_value == expected