Removed identical local copies from 45 test files. These fixtures are already defined in conftest.py.
229 lines
7.4 KiB
Python
229 lines
7.4 KiB
Python
"""Tests for the commands listing command."""
|
|
|
|
from pathlib import Path
|
|
|
|
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 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 combat_moves():
|
|
"""Load and register combat moves from content directory."""
|
|
from mudlib.combat.commands import register_combat_commands
|
|
|
|
combat_dir = Path(__file__).resolve().parents[1] / "content" / "combat"
|
|
register_combat_commands(combat_dir)
|
|
|
|
from mudlib.combat import commands as combat_cmds
|
|
|
|
yield combat_cmds.combat_moves
|
|
|
|
# Clean up
|
|
combat_cmds.combat_moves = {}
|
|
# Note: commands stay registered in _registry, but that's ok for tests
|
|
|
|
|
|
@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 show some specific commands with their primary names
|
|
assert "north" in output
|
|
assert "look" in output
|
|
assert "quit" in output
|
|
assert "commands" in output
|
|
|
|
# Should not contain combat moves
|
|
assert "punch" not in output
|
|
assert "roundhouse" not in output
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_commands_clean_names_no_parens(player):
|
|
"""Test that command names are shown cleanly without alias parens."""
|
|
await commands.dispatch(player, "commands")
|
|
output = "".join([call[0][0] for call in player.writer.write.call_args_list])
|
|
|
|
# Commands should appear without parens
|
|
assert "north" in output
|
|
assert "look" in output
|
|
assert "quit" in output
|
|
assert "commands" in output
|
|
|
|
# Should NOT show aliases in parens
|
|
assert "north(n)" not in output
|
|
assert "look(l)" not in output
|
|
assert "quit(q)" not in output
|
|
assert "commands(cmds)" not 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_sorted_alphabetically(player):
|
|
"""Test that commands are sorted alphabetically."""
|
|
await commands.dispatch(player, "commands")
|
|
output = "".join([call[0][0] for call in player.writer.write.call_args_list])
|
|
|
|
# All commands should appear in a single sorted list
|
|
assert "north" in output
|
|
assert "east" in output
|
|
assert "quit" in output
|
|
assert "look" in output
|
|
|
|
|
|
@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 as commands
|
|
assert "north" in output
|
|
assert "look" in output
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_commands_detail_regular_command(player):
|
|
"""Test commands detail view for a regular command."""
|
|
await commands.dispatch(player, "commands look")
|
|
output = "".join([call[0][0] for call in player.writer.write.call_args_list])
|
|
|
|
assert "look" in output
|
|
assert "aliases: l" in output
|
|
assert "mode: normal" in output
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_commands_detail_simple_combat_move(player, combat_moves):
|
|
"""Test commands detail view for a simple combat move."""
|
|
await commands.dispatch(player, "commands roundhouse")
|
|
output = "".join([call[0][0] for call in player.writer.write.call_args_list])
|
|
|
|
assert "roundhouse" in output
|
|
assert "type: attack" in output
|
|
assert "stamina: 8.0" in output
|
|
assert "hit time: 3000ms" in output
|
|
assert "damage: 25%" in output
|
|
assert "{attacker} shifts {his} weight back..." in output
|
|
assert "countered by: duck, parry high, parry low" in output
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_commands_detail_variant_base(player, combat_moves):
|
|
"""Test commands detail view for a variant base command."""
|
|
await commands.dispatch(player, "commands punch")
|
|
output = "".join([call[0][0] for call in player.writer.write.call_args_list])
|
|
|
|
assert "punch" in output
|
|
assert "type: attack" in output
|
|
|
|
# Should show both variants
|
|
assert "punch left" in output
|
|
assert "{attacker} retracts {his} left arm..." in output
|
|
assert "countered by: dodge right, parry high" in output
|
|
|
|
assert "punch right" in output
|
|
assert "{attacker} retracts {his} right arm..." in output
|
|
assert "countered by: dodge left, parry high" in output
|
|
|
|
# Should show shared properties in each variant
|
|
assert "stamina: 5.0" in output
|
|
assert "hit time: 3000ms" in output
|
|
assert "damage: 15%" in output
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_commands_detail_specific_variant(player, combat_moves):
|
|
"""Test commands detail view for a specific variant."""
|
|
await commands.dispatch(player, "commands punch left")
|
|
output = "".join([call[0][0] for call in player.writer.write.call_args_list])
|
|
|
|
assert "punch left" in output
|
|
assert "type: attack" in output
|
|
assert "stamina: 5.0" in output
|
|
assert "hit time: 3000ms" in output
|
|
assert "damage: 15%" in output
|
|
assert "{attacker} retracts {his} left arm..." in output
|
|
assert "countered by: dodge right, parry high" in output
|
|
|
|
# Should NOT show "punch right"
|
|
assert "punch right" not in output
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_commands_detail_unknown_command(player):
|
|
"""Test commands detail view for an unknown command."""
|
|
await commands.dispatch(player, "commands nonexistent")
|
|
output = "".join([call[0][0] for call in player.writer.write.call_args_list])
|
|
|
|
assert "Unknown command: nonexistent" in output
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_commands_detail_via_prefix(player, combat_moves):
|
|
"""Test commands detail view via prefix matching."""
|
|
await commands.dispatch(player, "commands ro")
|
|
output = "".join([call[0][0] for call in player.writer.write.call_args_list])
|
|
|
|
# Should show the full command details via prefix match
|
|
assert "roundhouse" in output
|
|
assert "type: attack" in output
|