from unittest.mock import AsyncMock, MagicMock import pytest from mudlib.commands.use import cmd_use from mudlib.player import Player from mudlib.thing import Thing from mudlib.verbs import verb from mudlib.zone import Zone @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 test_zone(): terrain = [["." for _ in range(10)] for _ in range(10)] return Zone(name="testzone", width=10, height=10, terrain=terrain) @pytest.fixture def player(mock_reader, mock_writer, test_zone): return Player( name="TestPlayer", x=5, y=5, reader=mock_reader, writer=mock_writer, location=test_zone, ) def get_output(mock_writer): """Extract all text written to the mock writer.""" return "".join(call[0][0] for call in mock_writer.write.call_args_list) @pytest.mark.asyncio async def test_use_no_args(player, mock_writer): """use with no args should prompt for what to use""" await cmd_use(player, "") output = get_output(mock_writer) assert "Use what?" in output @pytest.mark.asyncio async def test_use_object_with_verb(player, mock_writer, test_zone): """use rock should find rock with use verb and call it""" class Rock(Thing): @verb("use") async def use_verb(self, player, args): await player.send("You use the rock.\r\n") _rock = Rock( name="rock", description="a smooth rock", portable=True, location=test_zone ) _rock.x = 5 _rock.y = 5 await cmd_use(player, "rock") output = get_output(mock_writer) assert "You use the rock." in output @pytest.mark.asyncio async def test_use_object_without_verb(player, mock_writer, test_zone): """use rock when rock has no use verb should give error""" _rock = Thing( name="rock", description="a smooth rock", portable=True, location=test_zone ) _rock.x = 5 _rock.y = 5 await cmd_use(player, "rock") output = get_output(mock_writer) assert "You can't use that." in output @pytest.mark.asyncio async def test_use_object_not_found(player, mock_writer): """use flurb when nothing matches should give error""" await cmd_use(player, "flurb") output = get_output(mock_writer) assert "You don't see that here." in output @pytest.mark.asyncio async def test_use_object_on_target(player, mock_writer, test_zone): """use key on chest should pass chest as args to verb""" class Key(Thing): @verb("use") async def use_verb(self, player, args): await player.send(f"You use the key on {args}.\r\n") _key = Key(name="key", description="a brass key", portable=True, location=test_zone) _key.x = 5 _key.y = 5 await cmd_use(player, "key on chest") output = get_output(mock_writer) assert "You use the key on chest." in output @pytest.mark.asyncio async def test_use_object_on_nonexistent_target(player, mock_writer, test_zone): """use key on flurb should still work, passing flurb to verb handler""" class Key(Thing): @verb("use") async def use_verb(self, player, args): await player.send(f"You use the key on {args}.\r\n") _key = Key(name="key", description="a brass key", portable=True, location=test_zone) _key.x = 5 _key.y = 5 await cmd_use(player, "key on flurb") output = get_output(mock_writer) assert "You use the key on flurb." in output @pytest.mark.asyncio async def test_use_object_in_inventory(player, mock_writer): """use should find objects in inventory""" class Potion(Thing): @verb("use") async def use_verb(self, player, args): await player.send("You drink the potion.\r\n") _potion = Potion( name="potion", description="a healing potion", portable=True, location=player ) await cmd_use(player, "potion") output = get_output(mock_writer) assert "You drink the potion." in output @pytest.mark.asyncio async def test_use_passes_correct_args(player, mock_writer, test_zone): """verify verb handler receives correct args string""" received_args = None class Tool(Thing): @verb("use") async def use_verb(self, player, args): nonlocal received_args received_args = args await player.send(f"Used with args: '{args}'\r\n") _tool = Tool( name="tool", description="a multi-tool", portable=True, location=test_zone ) _tool.x = 5 _tool.y = 5 # Test with no target await cmd_use(player, "tool") assert received_args == "" # Reset writer mock_writer.write.reset_mock() received_args = None # Test with target await cmd_use(player, "tool on something") assert received_args == "something"