diff --git a/tests/test_cli_init.py b/tests/test_cli_init.py index 445f5d42a3..2e6d7f583d 100644 --- a/tests/test_cli_init.py +++ b/tests/test_cli_init.py @@ -3,217 +3,13 @@ that only manifest at runtime (not in mocked unit tests).""" import os import sys -import types -from contextlib import nullcontext -from unittest.mock import patch, MagicMock - -import pytest +from unittest.mock import patch sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) -def _install_prompt_toolkit_stubs(): - """Provide minimal prompt_toolkit shims for non-TUI unit tests.""" - if "prompt_toolkit" in sys.modules: - return - - class _StubBase: - def __init__(self, *args, **kwargs): - pass - - def __call__(self, *args, **kwargs): - return None - - def __getattr__(self, _name): - return lambda *args, **kwargs: None - - class _StubStyle: - @classmethod - def from_dict(cls, *_args, **_kwargs): - return cls() - - prompt_toolkit = types.ModuleType("prompt_toolkit") - prompt_toolkit.print_formatted_text = lambda *args, **kwargs: None - - history = types.ModuleType("prompt_toolkit.history") - history.FileHistory = _StubBase - - styles = types.ModuleType("prompt_toolkit.styles") - styles.Style = _StubStyle - - patch_stdout = types.ModuleType("prompt_toolkit.patch_stdout") - patch_stdout.patch_stdout = nullcontext - - application = types.ModuleType("prompt_toolkit.application") - application.Application = _StubBase - - layout = types.ModuleType("prompt_toolkit.layout") - layout.Layout = _StubBase - layout.HSplit = _StubBase - layout.Window = _StubBase - layout.FormattedTextControl = _StubBase - layout.ConditionalContainer = _StubBase - - processors = types.ModuleType("prompt_toolkit.layout.processors") - processors.Processor = _StubBase - processors.Transformation = _StubBase - processors.PasswordProcessor = _StubBase - processors.ConditionalProcessor = _StubBase - - filters = types.ModuleType("prompt_toolkit.filters") - filters.Condition = lambda fn: fn - - dimension = types.ModuleType("prompt_toolkit.layout.dimension") - dimension.Dimension = _StubBase - - menus = types.ModuleType("prompt_toolkit.layout.menus") - menus.CompletionsMenu = _StubBase - - widgets = types.ModuleType("prompt_toolkit.widgets") - widgets.TextArea = _StubBase - - key_binding = types.ModuleType("prompt_toolkit.key_binding") - key_binding.KeyBindings = _StubBase - - completion = types.ModuleType("prompt_toolkit.completion") - completion.Completer = object - completion.Completion = _StubBase - - formatted_text = types.ModuleType("prompt_toolkit.formatted_text") - formatted_text.ANSI = str - - sys.modules.update( - { - "prompt_toolkit": prompt_toolkit, - "prompt_toolkit.history": history, - "prompt_toolkit.styles": styles, - "prompt_toolkit.patch_stdout": patch_stdout, - "prompt_toolkit.application": application, - "prompt_toolkit.layout": layout, - "prompt_toolkit.layout.processors": processors, - "prompt_toolkit.filters": filters, - "prompt_toolkit.layout.dimension": dimension, - "prompt_toolkit.layout.menus": menus, - "prompt_toolkit.widgets": widgets, - "prompt_toolkit.key_binding": key_binding, - "prompt_toolkit.completion": completion, - "prompt_toolkit.formatted_text": formatted_text, - } - ) - - -def _install_rich_stubs(): - """Provide minimal rich shims for CLI unit tests.""" - if "rich" in sys.modules: - return - - rich = types.ModuleType("rich") - console = types.ModuleType("rich.console") - panel = types.ModuleType("rich.panel") - table = types.ModuleType("rich.table") - - class _RichStub: - def __init__(self, *args, **kwargs): - pass - - def __call__(self, *args, **kwargs): - return None - - def __getattr__(self, _name): - return lambda *args, **kwargs: None - - console.Console = _RichStub - panel.Panel = _RichStub - table.Table = _RichStub - - sys.modules.update( - { - "rich": rich, - "rich.console": console, - "rich.panel": panel, - "rich.table": table, - } - ) - - -def _install_cli_dependency_stubs(): - """Stub heavy runtime-only dependencies so CLI unit tests stay lightweight.""" - if "fire" not in sys.modules: - sys.modules["fire"] = types.ModuleType("fire") - - if "run_agent" not in sys.modules: - run_agent = types.ModuleType("run_agent") - run_agent.AIAgent = object - sys.modules["run_agent"] = run_agent - - if "model_tools" not in sys.modules: - model_tools = types.ModuleType("model_tools") - model_tools.get_tool_definitions = lambda *args, **kwargs: [] - model_tools.get_toolset_for_tool = lambda *args, **kwargs: None - sys.modules["model_tools"] = model_tools - - if "hermes_cli.banner" not in sys.modules: - banner = types.ModuleType("hermes_cli.banner") - banner.cprint = lambda *args, **kwargs: None - banner._GOLD = banner._BOLD = banner._DIM = banner._RST = "" - banner.VERSION = "test" - banner.HERMES_AGENT_LOGO = "" - banner.HERMES_CADUCEUS = "" - banner.COMPACT_BANNER = "" - banner.get_available_skills = lambda *args, **kwargs: [] - banner.build_welcome_banner = lambda *args, **kwargs: "" - sys.modules.setdefault("hermes_cli", types.ModuleType("hermes_cli")) - sys.modules["hermes_cli.banner"] = banner - - if "hermes_cli.commands" not in sys.modules: - commands = types.ModuleType("hermes_cli.commands") - commands.COMMANDS = {} - commands.SlashCommandCompleter = object - sys.modules["hermes_cli.commands"] = commands - - if "hermes_cli.callbacks" not in sys.modules: - callbacks = types.ModuleType("hermes_cli.callbacks") - callbacks.register_approval_callback = lambda *args, **kwargs: None - callbacks.register_sudo_password_callback = lambda *args, **kwargs: None - sys.modules["hermes_cli.callbacks"] = callbacks - sys.modules.setdefault("hermes_cli", types.ModuleType("hermes_cli")).callbacks = callbacks - - if "toolsets" not in sys.modules: - toolsets = types.ModuleType("toolsets") - toolsets.get_all_toolsets = lambda *args, **kwargs: [] - toolsets.get_toolset_info = lambda *args, **kwargs: {} - toolsets.resolve_toolset = lambda *args, **kwargs: [] - toolsets.validate_toolset = lambda *_args, **_kwargs: True - sys.modules["toolsets"] = toolsets - - if "cron" not in sys.modules: - cron = types.ModuleType("cron") - cron.create_job = lambda *args, **kwargs: None - cron.list_jobs = lambda *args, **kwargs: [] - cron.remove_job = lambda *args, **kwargs: None - cron.get_job = lambda *args, **kwargs: None - sys.modules["cron"] = cron - - sys.modules.setdefault("tools", types.ModuleType("tools")) - - if "tools.terminal_tool" not in sys.modules: - terminal_tool = types.ModuleType("tools.terminal_tool") - terminal_tool.cleanup_all_environments = lambda *args, **kwargs: None - terminal_tool.set_sudo_password_callback = lambda *args, **kwargs: None - terminal_tool.set_approval_callback = lambda *args, **kwargs: None - sys.modules["tools.terminal_tool"] = terminal_tool - - if "tools.browser_tool" not in sys.modules: - browser_tool = types.ModuleType("tools.browser_tool") - browser_tool._emergency_cleanup_all_sessions = lambda *args, **kwargs: None - sys.modules["tools.browser_tool"] = browser_tool - - def _make_cli(env_overrides=None, **kwargs): """Create a HermesCLI instance with minimal mocking.""" - _install_prompt_toolkit_stubs() - _install_rich_stubs() - _install_cli_dependency_stubs() import cli as _cli_mod from cli import HermesCLI _clean_config = {