"""Tests for readable objects.""" from unittest.mock import AsyncMock, MagicMock import pytest from mudlib.player import Player, players from mudlib.thing import Thing from mudlib.zone import Zone @pytest.fixture(autouse=True) def clear_state(): players.clear() yield players.clear() @pytest.fixture def zone(): terrain = [["." for _ in range(10)] for _ in range(10)] return Zone( name="library", width=10, height=10, terrain=terrain, ) @pytest.fixture def mock_writer(): writer = MagicMock() writer.write = MagicMock() writer.drain = AsyncMock() return writer @pytest.fixture def mock_reader(): return MagicMock() # --- Thing model --- def test_thing_readable_text_default(): """Thing has empty readable_text by default.""" t = Thing(name="rock") assert t.readable_text == "" def test_thing_readable_text_set(): """Thing can have readable_text.""" t = Thing(name="sign", readable_text="welcome to town") assert t.readable_text == "welcome to town" # --- Template loading --- def test_thing_template_readable_text(): """ThingTemplate parses readable_text from TOML data.""" import pathlib import tempfile from mudlib.things import load_thing_template with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f: f.write(""" name = "old sign" description = "a weathered wooden sign" portable = false readable_text = "beware of the goblin king" """) temp_path = pathlib.Path(f.name) try: template = load_thing_template(temp_path) assert template.readable_text == "beware of the goblin king" finally: temp_path.unlink() def test_thing_template_readable_text_default(): """ThingTemplate defaults readable_text to empty string.""" import pathlib import tempfile from mudlib.things import load_thing_template with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f: f.write(""" name = "rock" description = "a plain rock" """) temp_path = pathlib.Path(f.name) try: template = load_thing_template(temp_path) assert template.readable_text == "" finally: temp_path.unlink() def test_spawn_thing_readable_text(): """spawn_thing passes readable_text to Thing instance.""" from mudlib.things import ThingTemplate, spawn_thing template = ThingTemplate( name="notice", description="a posted notice", readable_text="town meeting at noon", ) thing = spawn_thing(template, location=None) assert thing.readable_text == "town meeting at noon" # --- Read command --- @pytest.mark.asyncio async def test_read_thing_on_ground(zone, mock_writer, mock_reader): """Reading a thing on the ground shows its text.""" from mudlib.commands.read import cmd_read player = Player( name="reader", x=5, y=5, writer=mock_writer, reader=mock_reader, location=zone, ) zone._contents.append(player) players["reader"] = player Thing( name="sign", description="a wooden sign", readable_text="welcome to the forest", location=zone, x=5, y=5, ) await cmd_read(player, "sign") mock_writer.write.assert_called() written = mock_writer.write.call_args_list[-1][0][0] assert "welcome to the forest" in written @pytest.mark.asyncio async def test_read_thing_in_inventory(zone, mock_writer, mock_reader): """Reading a thing in inventory shows its text.""" from mudlib.commands.read import cmd_read player = Player( name="reader", x=5, y=5, writer=mock_writer, reader=mock_reader, location=zone, ) zone._contents.append(player) players["reader"] = player Thing( name="scroll", description="an ancient scroll", readable_text="the ancient prophecy speaks of...", location=player, ) await cmd_read(player, "scroll") mock_writer.write.assert_called() written = mock_writer.write.call_args_list[-1][0][0] assert "the ancient prophecy speaks of" in written @pytest.mark.asyncio async def test_read_no_target(zone, mock_writer, mock_reader): """Reading without a target shows error.""" from mudlib.commands.read import cmd_read player = Player( name="reader", x=5, y=5, writer=mock_writer, reader=mock_reader, location=zone, ) zone._contents.append(player) await cmd_read(player, "") mock_writer.write.assert_called() written = mock_writer.write.call_args_list[0][0][0] assert "read what" in written.lower() @pytest.mark.asyncio async def test_read_not_found(zone, mock_writer, mock_reader): """Reading something not present shows error.""" from mudlib.commands.read import cmd_read player = Player( name="reader", x=5, y=5, writer=mock_writer, reader=mock_reader, location=zone, ) zone._contents.append(player) await cmd_read(player, "scroll") mock_writer.write.assert_called() written = mock_writer.write.call_args_list[0][0][0] assert "don't see" in written.lower() or "nothing" in written.lower() @pytest.mark.asyncio async def test_read_not_readable(zone, mock_writer, mock_reader): """Reading a thing with no readable_text shows error.""" from mudlib.commands.read import cmd_read player = Player( name="reader", x=5, y=5, writer=mock_writer, reader=mock_reader, location=zone, ) zone._contents.append(player) Thing( name="rock", description="a plain rock", location=zone, x=5, y=5, ) await cmd_read(player, "rock") mock_writer.write.assert_called() written = mock_writer.write.call_args_list[0][0][0] assert "nothing to read" in written.lower() @pytest.mark.asyncio async def test_read_by_alias(zone, mock_writer, mock_reader): """Can read a thing by its alias.""" from mudlib.commands.read import cmd_read player = Player( name="reader", x=5, y=5, writer=mock_writer, reader=mock_reader, location=zone, ) zone._contents.append(player) Thing( name="leather-bound book", aliases=["book", "tome"], description="a leather-bound book", readable_text="once upon a time...", location=zone, x=5, y=5, ) await cmd_read(player, "tome") mock_writer.write.assert_called() written = mock_writer.write.call_args_list[-1][0][0] assert "once upon a time" in written