Removed identical local copies from 45 test files. These fixtures are already defined in conftest.py.
206 lines
6.2 KiB
Python
206 lines
6.2 KiB
Python
"""Tests for variant prefix matching in combat commands."""
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from mudlib.combat import commands as combat_commands
|
|
from mudlib.combat.engine import active_encounters
|
|
from mudlib.combat.moves import load_moves
|
|
from mudlib.player import Player, players
|
|
from mudlib.zone import Zone
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def clear_state():
|
|
"""Clear encounters and players before and after each test."""
|
|
active_encounters.clear()
|
|
players.clear()
|
|
yield
|
|
active_encounters.clear()
|
|
players.clear()
|
|
|
|
|
|
@pytest.fixture
|
|
def test_zone():
|
|
"""Create a test zone for players."""
|
|
terrain = [["." for _ in range(256)] for _ in range(256)]
|
|
zone = Zone(
|
|
name="testzone",
|
|
width=256,
|
|
height=256,
|
|
toroidal=True,
|
|
terrain=terrain,
|
|
impassable=set(),
|
|
)
|
|
return zone
|
|
|
|
|
|
@pytest.fixture
|
|
def player(mock_reader, mock_writer, test_zone):
|
|
p = Player(name="Goku", x=0, y=0, reader=mock_reader, writer=mock_writer)
|
|
p.location = test_zone
|
|
test_zone._contents.append(p)
|
|
players[p.name] = p
|
|
return p
|
|
|
|
|
|
@pytest.fixture
|
|
def target(mock_reader, mock_writer, test_zone):
|
|
t = Player(name="Vegeta", x=0, y=0, reader=mock_reader, writer=mock_writer)
|
|
t.location = test_zone
|
|
test_zone._contents.append(t)
|
|
players[t.name] = t
|
|
return t
|
|
|
|
|
|
@pytest.fixture
|
|
def moves():
|
|
"""Load combat moves from content directory."""
|
|
content_dir = Path(__file__).parent.parent / "content" / "combat"
|
|
return load_moves(content_dir)
|
|
|
|
|
|
# --- variant prefix matching tests ---
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_exact_match_still_works(player, target, moves):
|
|
"""Test that exact variant names still work (e.g., 'high' matches 'high')."""
|
|
variant_moves = {
|
|
"high": moves["parry high"],
|
|
"low": moves["parry low"],
|
|
}
|
|
handler = combat_commands.make_variant_handler(
|
|
"parry", variant_moves, combat_commands.do_defend
|
|
)
|
|
|
|
await handler(player, "high")
|
|
|
|
# Should succeed without error
|
|
messages = [call[0][0] for call in player.writer.write.call_args_list]
|
|
assert not any("unknown" in msg.lower() for msg in messages)
|
|
assert not any("ambiguous" in msg.lower() for msg in messages)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_prefix_match_works(player, target, moves):
|
|
"""Test that prefix matching resolves unique prefixes (e.g., 'hi' -> 'high')."""
|
|
variant_moves = {
|
|
"high": moves["parry high"],
|
|
"low": moves["parry low"],
|
|
}
|
|
handler = combat_commands.make_variant_handler(
|
|
"parry", variant_moves, combat_commands.do_defend
|
|
)
|
|
|
|
# Test "hi" -> "high"
|
|
player.writer.write.reset_mock()
|
|
await handler(player, "hi")
|
|
messages = [call[0][0] for call in player.writer.write.call_args_list]
|
|
assert not any("unknown" in msg.lower() for msg in messages)
|
|
assert not any("ambiguous" in msg.lower() for msg in messages)
|
|
|
|
# Test "lo" -> "low"
|
|
player.writer.write.reset_mock()
|
|
await handler(player, "lo")
|
|
messages = [call[0][0] for call in player.writer.write.call_args_list]
|
|
assert not any("unknown" in msg.lower() for msg in messages)
|
|
assert not any("ambiguous" in msg.lower() for msg in messages)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_ambiguous_prefix_shows_disambiguation(player, moves):
|
|
"""Test that ambiguous prefix shows options (e.g., 'l' for 'left'/'long')."""
|
|
# Create hypothetical moves with conflicting prefixes
|
|
variant_moves = {
|
|
"left": moves["punch left"],
|
|
"long": moves["punch left"], # reuse same move, just for testing keys
|
|
}
|
|
handler = combat_commands.make_variant_handler(
|
|
"punch", variant_moves, combat_commands.do_attack
|
|
)
|
|
|
|
await handler(player, "l")
|
|
|
|
messages = [call[0][0] for call in player.writer.write.call_args_list]
|
|
output = "".join(messages).lower()
|
|
assert "ambiguous" in output
|
|
assert "left" in output
|
|
assert "long" in output
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_no_match_shows_error(player, moves):
|
|
"""Test that no matching variant shows error with valid options."""
|
|
variant_moves = {
|
|
"high": moves["parry high"],
|
|
"low": moves["parry low"],
|
|
}
|
|
handler = combat_commands.make_variant_handler(
|
|
"parry", variant_moves, combat_commands.do_defend
|
|
)
|
|
|
|
await handler(player, "middle")
|
|
|
|
messages = [call[0][0] for call in player.writer.write.call_args_list]
|
|
output = "".join(messages).lower()
|
|
assert "unknown" in output
|
|
assert "high" in output or "low" in output
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_prefix_with_target_args(player, target, moves):
|
|
"""Test that prefix matching preserves target arguments."""
|
|
variant_moves = {
|
|
"left": moves["punch left"],
|
|
"right": moves["punch right"],
|
|
}
|
|
handler = combat_commands.make_variant_handler(
|
|
"punch", variant_moves, combat_commands.do_attack
|
|
)
|
|
|
|
await handler(player, "le Vegeta")
|
|
|
|
# Should start combat with target
|
|
from mudlib.combat.engine import get_encounter
|
|
|
|
encounter = get_encounter(player)
|
|
assert encounter is not None
|
|
assert encounter.defender is target
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_single_char_prefix_match(player, moves):
|
|
"""Test that single-char prefix works when unambiguous (e.g., 'h' -> 'high')."""
|
|
variant_moves = {
|
|
"high": moves["parry high"],
|
|
"low": moves["parry low"],
|
|
}
|
|
handler = combat_commands.make_variant_handler(
|
|
"parry", variant_moves, combat_commands.do_defend
|
|
)
|
|
|
|
await handler(player, "h")
|
|
|
|
messages = [call[0][0] for call in player.writer.write.call_args_list]
|
|
assert not any("unknown" in msg.lower() for msg in messages)
|
|
assert not any("ambiguous" in msg.lower() for msg in messages)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_case_insensitive_prefix_match(player, moves):
|
|
"""Test that prefix matching is case-insensitive."""
|
|
variant_moves = {
|
|
"high": moves["parry high"],
|
|
"low": moves["parry low"],
|
|
}
|
|
handler = combat_commands.make_variant_handler(
|
|
"parry", variant_moves, combat_commands.do_defend
|
|
)
|
|
|
|
await handler(player, "HI")
|
|
|
|
messages = [call[0][0] for call in player.writer.write.call_args_list]
|
|
assert not any("unknown" in msg.lower() for msg in messages)
|
|
assert not any("ambiguous" in msg.lower() for msg in messages)
|