mud/tests/test_help_command.py

137 lines
4.1 KiB
Python

"""Tests for the standalone help command."""
from unittest.mock import AsyncMock, MagicMock
import pytest
from mudlib import commands
# Import command modules to register their commands
from mudlib.commands import (
help, # noqa: F401
look, # noqa: F401
movement, # noqa: F401
)
from mudlib.commands.help import _help_topics
from mudlib.content import load_help_topics
@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.fixture
def admin_player(mock_reader, mock_writer):
from mudlib.player import Player
p = Player(name="AdminPlayer", x=5, y=5, reader=mock_reader, writer=mock_writer)
p.is_admin = True
return p
@pytest.fixture(autouse=True)
def _load_zones_topic():
"""Load the zones help topic for tests that need it."""
from pathlib import Path
help_dir = Path(__file__).resolve().parents[1] / "content" / "help"
if help_dir.exists():
loaded = load_help_topics(help_dir)
_help_topics.update(loaded)
yield
_help_topics.clear()
@pytest.mark.asyncio
async def test_help_command_is_registered():
"""The help command should be registered in the command registry."""
assert "help" in commands._registry
@pytest.mark.asyncio
async def test_help_has_wildcard_mode():
"""Help should work from any mode."""
cmd_def = commands._registry["help"]
assert cmd_def.mode == "*"
@pytest.mark.asyncio
async def test_help_no_args_shows_usage(player):
"""help with no args shows usage hint."""
await commands.dispatch(player, "help")
output = "".join([call[0][0] for call in player.writer.write.call_args_list])
assert "help <command>" in output
assert "commands" in output
assert "skills" in output
@pytest.mark.asyncio
async def test_help_known_command_shows_detail(player):
"""help <known command> shows detail view."""
await commands.dispatch(player, "help look")
output = "".join([call[0][0] for call in player.writer.write.call_args_list])
assert "look" in output.lower()
assert "mode:" in output.lower()
@pytest.mark.asyncio
async def test_help_unknown_command_shows_error(player):
"""help <unknown> shows error message."""
await commands.dispatch(player, "help nonexistent")
output = "".join([call[0][0] for call in player.writer.write.call_args_list])
assert "nonexistent" in output.lower()
assert "unknown" in output.lower() or "not found" in output.lower()
@pytest.mark.asyncio
async def test_help_and_commands_both_exist():
"""Both help and commands should be registered independently."""
assert "help" in commands._registry
assert "commands" in commands._registry
# They should be different functions
assert commands._registry["help"].handler != commands._registry["commands"].handler
@pytest.mark.asyncio
async def test_help_zones_shows_guide(admin_player):
"""help zones shows zone guide text with command references."""
await commands.dispatch(admin_player, "help zones")
output = "".join([call[0][0] for call in admin_player.writer.write.call_args_list])
assert "zones" in output
assert "@zones" in output
assert "@goto" in output
assert "@dig" in output
assert "@paint" in output
assert "@save" in output
@pytest.mark.asyncio
async def test_help_zones_shows_see_also(admin_player):
"""help zones output contains see also cross-references."""
await commands.dispatch(admin_player, "help zones")
output = "".join([call[0][0] for call in admin_player.writer.write.call_args_list])
assert "see:" in output
@pytest.mark.asyncio
async def test_help_zones_requires_admin(player):
"""Non-admin players cannot see admin help topics."""
await commands.dispatch(player, "help zones")
output = "".join([call[0][0] for call in player.writer.write.call_args_list])
assert "unknown" in output.lower()