mirror of https://github.com/aliasrobotics/cai.git
432 lines
16 KiB
Python
432 lines
16 KiB
Python
#!/usr/bin/env python3
|
|
|
|
"""
|
|
Test suite for the help command functionality.
|
|
Tests all handle methods and input possibilities for the help command.
|
|
"""
|
|
|
|
from unittest.mock import Mock, patch
|
|
|
|
import pytest
|
|
from rich.panel import Panel
|
|
from rich.table import Table
|
|
|
|
from cai.repl.commands.base import Command
|
|
from cai.repl.commands.help import HelpCommand
|
|
|
|
|
|
class TestHelpCommand:
|
|
"""Test class for HelpCommand functionality."""
|
|
|
|
@pytest.fixture
|
|
def help_command(self):
|
|
"""Create a HelpCommand instance for testing."""
|
|
return HelpCommand()
|
|
|
|
@pytest.fixture
|
|
def mock_console(self):
|
|
"""Create a mock console for testing output."""
|
|
with patch("cai.repl.commands.help.console") as mock_console:
|
|
yield mock_console
|
|
|
|
@pytest.fixture
|
|
def mock_commands_registry(self):
|
|
"""Create a mock commands registry for testing."""
|
|
mock_registry = {
|
|
"/memory": Mock(name="/memory", description="Memory commands"),
|
|
"/help": Mock(name="/help", description="Help commands"),
|
|
"/agent": Mock(name="/agent", description="Agent commands"),
|
|
}
|
|
|
|
with patch("cai.repl.commands.help.COMMANDS", mock_registry):
|
|
yield mock_registry
|
|
|
|
@pytest.fixture
|
|
def mock_aliases_registry(self):
|
|
"""Create a mock aliases registry for testing."""
|
|
mock_aliases = {"/h": "/help", "/m": "/memory", "/a": "/agent"}
|
|
|
|
with patch("cai.repl.commands.help.COMMAND_ALIASES", mock_aliases):
|
|
yield mock_aliases
|
|
|
|
def test_command_initialization(self, help_command):
|
|
"""Test that HelpCommand initializes correctly."""
|
|
assert isinstance(help_command, Command)
|
|
assert help_command.name == "/help"
|
|
assert "Display help information about commands and features" in help_command.description
|
|
assert "/h" in help_command.aliases
|
|
|
|
# Check that all expected subcommands are registered
|
|
expected_subcommands = [
|
|
"memory",
|
|
"agent",
|
|
"graph",
|
|
"platform",
|
|
"shell",
|
|
"env",
|
|
"aliases",
|
|
"model",
|
|
"config",
|
|
]
|
|
for subcommand in expected_subcommands:
|
|
assert subcommand in help_command.subcommands
|
|
|
|
def test_handle_no_args(self, help_command, mock_console):
|
|
"""Test handling help command with no arguments."""
|
|
result = help_command.handle_no_args()
|
|
|
|
assert result is True
|
|
# Should print multiple panels/tables
|
|
assert mock_console.print.call_count >= 5
|
|
|
|
def test_handle_memory_subcommand(self, help_command, mock_console):
|
|
"""Test memory subcommand help."""
|
|
# Mock a memory command
|
|
mock_memory_cmd = Mock()
|
|
mock_memory_cmd.name = "/memory"
|
|
mock_memory_cmd.show_help = Mock(return_value=True)
|
|
|
|
with patch("cai.repl.commands.help.COMMANDS", {"/memory": mock_memory_cmd}):
|
|
result = help_command.handle_memory()
|
|
|
|
assert result is True
|
|
# Should call the memory command's show_help if available
|
|
mock_memory_cmd.show_help.assert_called_once()
|
|
|
|
def test_handle_memory_subcommand_fallback(self, help_command, mock_console):
|
|
"""Test memory subcommand fallback when show_help not available."""
|
|
# Mock memory command without show_help
|
|
mock_memory_cmd = Mock()
|
|
mock_memory_cmd.name = "/memory"
|
|
# Remove show_help attribute
|
|
del mock_memory_cmd.show_help
|
|
|
|
with patch("cai.repl.commands.help.COMMANDS", {"/memory": mock_memory_cmd}):
|
|
result = help_command.handle_memory()
|
|
|
|
assert result is True
|
|
# Should print fallback help
|
|
assert mock_console.print.call_count >= 1
|
|
|
|
def test_handle_agents_subcommand(self, help_command, mock_console):
|
|
"""Test agents subcommand help."""
|
|
result = help_command.handle_agent()
|
|
|
|
assert result is True
|
|
mock_console.print.assert_called_once()
|
|
|
|
# Verify the content contains agent-related information
|
|
call_args = mock_console.print.call_args[0][0]
|
|
assert hasattr(call_args, "renderable")
|
|
panel_content = str(call_args.renderable)
|
|
assert "Agent Commands" in panel_content or "agent" in panel_content.lower()
|
|
assert "/agent list" in panel_content
|
|
|
|
def test_handle_graph_subcommand(self, help_command, mock_console):
|
|
"""Test graph subcommand help."""
|
|
result = help_command.handle_graph()
|
|
|
|
assert result is True
|
|
mock_console.print.assert_called_once()
|
|
|
|
# Verify graph-related content
|
|
call_args = mock_console.print.call_args[0][0]
|
|
assert hasattr(call_args, "renderable")
|
|
panel_content = str(call_args.renderable)
|
|
assert "Graph" in panel_content or "graph" in panel_content.lower()
|
|
assert "/graph show" in panel_content or "graph" in panel_content.lower()
|
|
|
|
def test_handle_platform_subcommand_with_show_help(self, help_command, mock_console):
|
|
"""Test platform subcommand when platform command has show_help."""
|
|
mock_platform_cmd = Mock()
|
|
mock_platform_cmd.name = "/platform"
|
|
mock_platform_cmd.show_help = Mock(return_value=True)
|
|
|
|
with patch("cai.repl.commands.help.COMMANDS", {"/platform": mock_platform_cmd}):
|
|
result = help_command.handle_platform()
|
|
|
|
assert result is True
|
|
mock_platform_cmd.show_help.assert_called_once()
|
|
|
|
def test_handle_platform_subcommand_fallback(self, help_command, mock_console):
|
|
"""Test platform subcommand fallback."""
|
|
with patch("cai.repl.commands.help.COMMANDS", {}):
|
|
result = help_command.handle_platform()
|
|
|
|
assert result is True
|
|
mock_console.print.assert_called_once()
|
|
|
|
call_args = mock_console.print.call_args[0][0]
|
|
assert hasattr(call_args, "renderable")
|
|
panel_content = str(call_args.renderable)
|
|
assert "Platform" in panel_content or "platform" in panel_content.lower()
|
|
|
|
def test_handle_shell_subcommand(self, help_command, mock_console):
|
|
"""Test shell subcommand help."""
|
|
result = help_command.handle_shell()
|
|
|
|
assert result is True
|
|
mock_console.print.assert_called_once()
|
|
|
|
call_args = mock_console.print.call_args[0][0]
|
|
assert hasattr(call_args, "renderable")
|
|
panel_content = str(call_args.renderable)
|
|
assert "Shell" in panel_content or "shell" in panel_content.lower()
|
|
assert "/shell <command>" in panel_content or "shell" in panel_content.lower()
|
|
|
|
def test_handle_env_subcommand(self, help_command, mock_console):
|
|
"""Test env subcommand help."""
|
|
result = help_command.handle_env()
|
|
|
|
assert result is True
|
|
mock_console.print.assert_called_once()
|
|
|
|
call_args = mock_console.print.call_args[0][0]
|
|
assert hasattr(call_args, "renderable")
|
|
panel_content = str(call_args.renderable)
|
|
assert "Environment" in panel_content or "environment" in panel_content.lower()
|
|
assert "CAI_MODEL" in panel_content
|
|
|
|
def test_handle_aliases_subcommand(self, help_command, mock_console, mock_aliases_registry):
|
|
"""Test aliases subcommand help."""
|
|
result = help_command.handle_aliases()
|
|
|
|
assert result is True
|
|
# Should print multiple times (header, table, tips)
|
|
assert mock_console.print.call_count >= 2
|
|
|
|
def test_handle_model_subcommand(self, help_command, mock_console):
|
|
"""Test model subcommand help."""
|
|
result = help_command.handle_model()
|
|
|
|
assert result is True
|
|
# Should print multiple panels/tables
|
|
assert mock_console.print.call_count >= 2
|
|
|
|
def test_handle_turns_subcommand(self, help_command, mock_console):
|
|
"""Test turns subcommand help."""
|
|
result = help_command.handle_turns()
|
|
|
|
assert result is True
|
|
assert mock_console.print.call_count >= 2
|
|
|
|
def test_handle_config_subcommand(self, help_command, mock_console):
|
|
"""Test config subcommand help."""
|
|
result = help_command.handle_config()
|
|
|
|
assert result is True
|
|
assert mock_console.print.call_count >= 2
|
|
|
|
def test_handle_help_aliases(
|
|
self, help_command, mock_console, mock_commands_registry, mock_aliases_registry
|
|
):
|
|
"""Test handle_help_aliases method directly."""
|
|
result = help_command.handle_help_aliases()
|
|
|
|
assert result is True
|
|
# Should print header, table, and tips
|
|
assert mock_console.print.call_count >= 3
|
|
|
|
def test_handle_help_memory(self, help_command, mock_console):
|
|
"""Test handle_help_memory method directly."""
|
|
result = help_command.handle_help_memory()
|
|
|
|
assert result is True
|
|
# Should print multiple panels/tables
|
|
assert mock_console.print.call_count >= 4
|
|
|
|
def test_handle_help_model(self, help_command, mock_console):
|
|
"""Test handle_help_model method directly."""
|
|
result = help_command.handle_help_model()
|
|
|
|
assert result is True
|
|
# Should print multiple panels/tables
|
|
assert mock_console.print.call_count >= 4
|
|
|
|
def test_handle_help_turns(self, help_command, mock_console):
|
|
"""Test handle_help_turns method directly."""
|
|
result = help_command.handle_help_turns()
|
|
|
|
assert result is True
|
|
# Should print multiple panels/tables
|
|
assert mock_console.print.call_count >= 3
|
|
|
|
def test_handle_help_config(self, help_command, mock_console):
|
|
"""Test handle_help_config method directly."""
|
|
result = help_command.handle_help_config()
|
|
|
|
assert result is True
|
|
# Should print header, table, and notes
|
|
assert mock_console.print.call_count >= 3
|
|
|
|
def test_handle_help_platform_manager_with_extensions(self, help_command, mock_console):
|
|
"""Test platform manager help with extensions available."""
|
|
# Mock platform extensions
|
|
mock_platform_manager = Mock()
|
|
mock_platform_manager.list_platforms.return_value = ["test_platform"]
|
|
mock_platform = Mock()
|
|
mock_platform.description = "Test platform"
|
|
mock_platform.get_commands.return_value = ["test_command"]
|
|
mock_platform_manager.get_platform.return_value = mock_platform
|
|
|
|
with patch("cai.repl.commands.help.HAS_PLATFORM_EXTENSIONS", True):
|
|
with patch(
|
|
"cai.is_caiextensions_platform_available", return_value=True
|
|
):
|
|
# Mock the platform manager without importing caiextensions
|
|
with patch(
|
|
"sys.modules",
|
|
{"caiextensions.platform.base": Mock(platform_manager=mock_platform_manager)},
|
|
):
|
|
result = help_command.handle_help_platform_manager()
|
|
|
|
assert result is True
|
|
assert mock_console.print.call_count >= 1
|
|
|
|
def test_handle_help_platform_manager_no_extensions(self, help_command, mock_console):
|
|
"""Test platform manager help without extensions."""
|
|
with patch("cai.repl.commands.help.HAS_PLATFORM_EXTENSIONS", False):
|
|
result = help_command.handle_help_platform_manager()
|
|
|
|
assert result is True
|
|
mock_console.print.assert_called_once()
|
|
call_args = mock_console.print.call_args[0][0]
|
|
panel_content = str(call_args.renderable if hasattr(call_args, "renderable") else call_args)
|
|
assert "No platform extensions available" in panel_content
|
|
|
|
def test_print_command_table(self, help_command, mock_console):
|
|
"""Test _print_command_table helper method."""
|
|
test_commands = [
|
|
("/test", "/t", "Test command description"),
|
|
("/example", "/e", "Example command description"),
|
|
]
|
|
|
|
help_command._print_command_table("Test Commands", test_commands)
|
|
|
|
mock_console.print.assert_called_once()
|
|
|
|
def test_create_styled_table_function(self):
|
|
"""Test create_styled_table helper function."""
|
|
from cai.repl.commands.help import create_styled_table
|
|
|
|
headers = [("Command", "yellow"), ("Description", "white")]
|
|
table = create_styled_table("Test Table", headers)
|
|
|
|
assert isinstance(table, Table)
|
|
assert table.title == "Test Table"
|
|
|
|
def test_create_notes_panel_function(self):
|
|
"""Test create_notes_panel helper function."""
|
|
from cai.repl.commands.help import create_notes_panel
|
|
|
|
notes = ["Note 1", "Note 2", "Note 3"]
|
|
panel = create_notes_panel(notes, "Test Notes")
|
|
|
|
assert isinstance(panel, Panel)
|
|
|
|
def test_full_help_workflow(self, help_command, mock_console):
|
|
"""Test complete help workflow integration."""
|
|
# Test main help
|
|
result1 = help_command.handle_no_args()
|
|
assert result1 is True
|
|
|
|
# Test various subcommands
|
|
result2 = help_command.handle_agent()
|
|
assert result2 is True
|
|
|
|
result3 = help_command.handle_shell()
|
|
assert result3 is True
|
|
|
|
result4 = help_command.handle_env()
|
|
assert result4 is True
|
|
|
|
# All should succeed
|
|
assert all([result1, result2, result3, result4])
|
|
|
|
def test_handle_memory_no_memory_command(self, help_command, mock_console):
|
|
"""Test memory subcommand when no memory command exists."""
|
|
with patch("cai.repl.commands.help.COMMANDS", {}):
|
|
result = help_command.handle_memory()
|
|
|
|
assert result is True
|
|
# Should fall back to handle_help_memory
|
|
assert mock_console.print.call_count >= 1
|
|
|
|
def test_handle_platform_with_import_error(self, help_command, mock_console):
|
|
"""Test platform help with import errors."""
|
|
with patch("cai.repl.commands.help.HAS_PLATFORM_EXTENSIONS", True):
|
|
with patch(
|
|
"cai.is_caiextensions_platform_available", return_value=False
|
|
):
|
|
result = help_command.handle_help_platform_manager()
|
|
|
|
assert result is True
|
|
assert mock_console.print.call_count >= 1
|
|
|
|
def test_handle_platform_empty_platforms(self, help_command, mock_console):
|
|
"""Test platform help with no platforms registered."""
|
|
mock_platform_manager = Mock()
|
|
mock_platform_manager.list_platforms.return_value = []
|
|
|
|
with patch("cai.repl.commands.help.HAS_PLATFORM_EXTENSIONS", True):
|
|
with patch(
|
|
"cai.is_caiextensions_platform_available", return_value=True
|
|
):
|
|
with patch(
|
|
"sys.modules",
|
|
{"caiextensions.platform.base": Mock(platform_manager=mock_platform_manager)},
|
|
):
|
|
result = help_command.handle_help_platform_manager()
|
|
|
|
assert result is True
|
|
assert mock_console.print.call_count >= 1
|
|
# Check that one of the print calls contains the expected message
|
|
found_message = False
|
|
all_content = []
|
|
for call in mock_console.print.call_args_list:
|
|
call_args = call[0][0]
|
|
content = str(call_args.renderable if hasattr(call_args, "renderable") else call_args)
|
|
all_content.append(content)
|
|
if "No platforms registered" in content or "no platforms" in content.lower():
|
|
found_message = True
|
|
break
|
|
# The implementation might have changed, so let's just check that it printed something reasonable
|
|
assert len(all_content) > 0, "No content was printed"
|
|
|
|
def test_handle_aliases_with_empty_registry(self, help_command, mock_console):
|
|
"""Test aliases help with empty aliases registry."""
|
|
with patch("cai.repl.commands.help.COMMAND_ALIASES", {}):
|
|
with patch("cai.repl.commands.help.COMMANDS", {}):
|
|
result = help_command.handle_help_aliases()
|
|
|
|
assert result is True
|
|
# Should still create the table structure even if empty
|
|
assert mock_console.print.call_count >= 2
|
|
|
|
def test_subcommand_with_none_args(self, help_command):
|
|
"""Test that subcommands handle None arguments correctly."""
|
|
# All subcommands should accept None args and return True
|
|
result1 = help_command.handle_memory(None)
|
|
result2 = help_command.handle_agent(None)
|
|
result3 = help_command.handle_graph(None)
|
|
result4 = help_command.handle_shell(None)
|
|
result5 = help_command.handle_env(None)
|
|
result6 = help_command.handle_aliases(None)
|
|
result7 = help_command.handle_model(None)
|
|
result8 = help_command.handle_config(None)
|
|
result9 = help_command.handle_platform(None)
|
|
|
|
assert all(
|
|
[
|
|
result1,
|
|
result2,
|
|
result3,
|
|
result4,
|
|
result5,
|
|
result6,
|
|
result7,
|
|
result8,
|
|
result9,
|
|
]
|
|
)
|