"""Tests for the commands listing command.""" from unittest.mock import AsyncMock, MagicMock import pytest from mudlib import commands # Import command modules to register their commands from mudlib.commands import ( edit, # noqa: F401 fly, # noqa: F401 help, # noqa: F401 look, # noqa: F401 movement, # noqa: F401 quit, # noqa: F401 ) @pytest.fixture def mock_writer(): writer = MagicMock() writer.write = MagicMock() writer.drain = AsyncMock() return writer @pytest.fixture def mock_reader(): return MagicMock() @pytest.fixture def player(mock_reader, mock_writer): from mudlib.player import Player return Player( name="TestPlayer", x=5, y=5, reader=mock_reader, writer=mock_writer, ) @pytest.mark.asyncio async def test_commands_command_exists(): """Test that commands command is registered.""" assert "commands" in commands._registry assert "cmds" in commands._registry assert commands._registry["commands"] is commands._registry["cmds"] @pytest.mark.asyncio async def test_commands_has_wildcard_mode(): """Test that commands works from any mode.""" assert commands._registry["commands"].mode == "*" @pytest.mark.asyncio async def test_commands_lists_all_commands(player): """Test that commands command lists all unique commands.""" # Execute the command await commands.dispatch(player, "commands") # Collect all output output = "".join([call[0][0] for call in player.writer.write.call_args_list]) # Should contain at least movement and other groups assert "Movement:" in output assert "Other:" in output # Should show some specific commands with their primary names assert "north" in output assert "look" in output assert "quit" in output assert "commands" in output @pytest.mark.asyncio async def test_commands_shows_aliases(player): """Test that aliases are shown in parens after command names.""" await commands.dispatch(player, "commands") output = "".join([call[0][0] for call in player.writer.write.call_args_list]) # Check that some aliases are shown in parentheses assert "north(n)" in output or "north (n)" in output assert "look(l)" in output or "look (l)" in output assert "quit(q)" in output or "quit (q)" in output assert "commands(cmds)" in output or "commands (cmds)" in output @pytest.mark.asyncio async def test_commands_deduplicates_entries(player): """Test that aliases don't create duplicate command entries.""" await commands.dispatch(player, "commands") output = "".join([call[0][0] for call in player.writer.write.call_args_list]) # Count how many times "north" appears as a primary command # It should appear once in the movement group, not multiple times # (Note: it might appear in parens as part of another command, but # we're checking it doesn't appear as a standalone entry multiple times) lines_with_north_command = [ line for line in output.split("\n") if line.strip().startswith("north") ] # Should only have one line starting with "north" as a command assert len(lines_with_north_command) <= 1 @pytest.mark.asyncio async def test_commands_groups_correctly(player): """Test that commands are grouped by type.""" await commands.dispatch(player, "commands") output = "".join([call[0][0] for call in player.writer.write.call_args_list]) # Find the groups movement_pos = output.find("Movement:") other_pos = output.find("Other:") # At minimum, movement and other should exist assert movement_pos != -1 assert other_pos != -1 # Check that movement commands appear in the movement section # (before the "Other:" section) movement_section = output[movement_pos:other_pos] assert "north" in movement_section assert "east" in movement_section # Check that non-movement commands appear in other section other_section = output[other_pos:] assert "quit" in other_section assert "look" in other_section @pytest.mark.asyncio async def test_commands_via_alias(player): """Test that the cmds alias works.""" await commands.dispatch(player, "cmds") output = "".join([call[0][0] for call in player.writer.write.call_args_list]) # Should produce the same output structure assert "Movement:" in output assert "Other:" in output