mud/tests/test_import_map.py
Jared Miller da76b6004e
Add YAML map import script with tests
Implements import_map.py script that converts YAML zone definitions to
TOML format used by the engine. YAML format supports all zone features
including terrain, portals, spawns, ambient messages, and boundaries.
2026-02-14 12:39:48 -05:00

285 lines
6.5 KiB
Python

"""Tests for YAML map import script."""
from __future__ import annotations
from pathlib import Path
import pytest
from mudlib.portal import Portal
from mudlib.zones import load_zone
def test_minimal_yaml_import(tmp_path: Path) -> None:
"""Test importing a minimal YAML map."""
yaml_content = """
name: test_zone
width: 5
height: 5
terrain:
rows:
- "....."
- "....."
- "....."
- "....."
- "....."
"""
yaml_file = tmp_path / "test_zone.yaml"
yaml_file.write_text(yaml_content)
# Import the script module
from scripts.import_map import import_map
output_file = import_map(yaml_file, tmp_path)
# Verify TOML was created
assert output_file.exists()
assert output_file.name == "test_zone.toml"
# Verify it can be loaded by existing zone loader
zone = load_zone(output_file)
assert zone.name == "test_zone"
assert zone.width == 5
assert zone.height == 5
assert zone.description == ""
assert zone.toroidal is True # default
assert zone.spawn_x == 0 # default
assert zone.spawn_y == 0 # default
assert zone.safe is False # default
assert len(zone.terrain) == 5
assert all(len(row) == 5 for row in zone.terrain)
def test_full_featured_yaml_import(tmp_path: Path) -> None:
"""Test importing a YAML map with all features."""
yaml_content = """
name: complex_zone
description: a complex test zone
width: 10
height: 10
toroidal: false
spawn: [5, 5]
safe: true
terrain:
rows:
- "##########"
- "#........#"
- "#........#"
- "#........#"
- "#........#"
- "#........#"
- "#........#"
- "#........#"
- "#........#"
- "##########"
impassable: ["#"]
ambient:
interval: 60
messages:
- "wind howls..."
- "a distant sound"
portals:
- x: 5
y: 0
target: "other_zone:10,10"
label: "a wide path"
aliases: ["path", "wide"]
spawns:
- mob: goblin
max_count: 3
respawn_seconds: 300
home_region:
x: [1, 9]
y: [1, 9]
"""
yaml_file = tmp_path / "complex_zone.yaml"
yaml_file.write_text(yaml_content)
from scripts.import_map import import_map
output_file = import_map(yaml_file, tmp_path)
# Load and verify all fields
zone = load_zone(output_file)
assert zone.name == "complex_zone"
assert zone.description == "a complex test zone"
assert zone.width == 10
assert zone.height == 10
assert zone.toroidal is False
assert zone.spawn_x == 5
assert zone.spawn_y == 5
assert zone.safe is True
# Verify terrain
assert len(zone.terrain) == 10
assert zone.terrain[0] == list("##########")
assert zone.terrain[1] == list("#........#")
# Verify impassable
assert "#" in zone.impassable
# Verify ambient messages
assert zone.ambient_messages == ["wind howls...", "a distant sound"]
assert zone.ambient_interval == 60
# Verify portals
portals = [obj for obj in zone._contents if isinstance(obj, Portal)]
assert len(portals) == 1
portal = portals[0]
assert portal.x == 5
assert portal.y == 0
assert portal.target_zone == "other_zone"
assert portal.target_x == 10
assert portal.target_y == 10
assert portal.name == "a wide path"
assert portal.aliases == ["path", "wide"]
# Verify spawn rules
assert len(zone.spawn_rules) == 1
spawn = zone.spawn_rules[0]
assert spawn.mob == "goblin"
assert spawn.max_count == 3
assert spawn.respawn_seconds == 300
assert spawn.home_region == {"x": [1, 9], "y": [1, 9]}
def test_missing_required_field_raises_error(tmp_path: Path) -> None:
"""Test that missing required fields raise appropriate errors."""
yaml_content = """
width: 5
height: 5
"""
yaml_file = tmp_path / "incomplete.yaml"
yaml_file.write_text(yaml_content)
from scripts.import_map import import_map
with pytest.raises(KeyError, match="name"):
import_map(yaml_file, tmp_path)
def test_spawn_list_format(tmp_path: Path) -> None:
"""Test that spawn coordinates as [x, y] list are parsed correctly."""
yaml_content = """
name: spawn_test
width: 3
height: 3
spawn: [1, 2]
terrain:
rows:
- "..."
- "..."
- "..."
"""
yaml_file = tmp_path / "spawn_test.yaml"
yaml_file.write_text(yaml_content)
from scripts.import_map import import_map
output_file = import_map(yaml_file, tmp_path)
zone = load_zone(output_file)
assert zone.spawn_x == 1
assert zone.spawn_y == 2
def test_defaults_applied(tmp_path: Path) -> None:
"""Test that sensible defaults are applied for optional fields."""
yaml_content = """
name: defaults_test
width: 3
height: 3
terrain:
rows:
- "..."
- "..."
- "..."
"""
yaml_file = tmp_path / "defaults_test.yaml"
yaml_file.write_text(yaml_content)
from scripts.import_map import import_map
output_file = import_map(yaml_file, tmp_path)
zone = load_zone(output_file)
# Verify defaults
assert zone.toroidal is True
assert zone.spawn_x == 0
assert zone.spawn_y == 0
assert zone.safe is False
assert zone.ambient_messages == []
assert zone.spawn_rules == []
def test_multiple_portals(tmp_path: Path) -> None:
"""Test importing multiple portals."""
yaml_content = """
name: multi_portal
width: 5
height: 5
terrain:
rows:
- "....."
- "....."
- "....."
- "....."
- "....."
portals:
- x: 0
y: 0
target: "zone1:5,5"
label: "north path"
- x: 4
y: 4
target: "zone2:0,0"
label: "south path"
"""
yaml_file = tmp_path / "multi_portal.yaml"
yaml_file.write_text(yaml_content)
from scripts.import_map import import_map
output_file = import_map(yaml_file, tmp_path)
zone = load_zone(output_file)
portals = [obj for obj in zone._contents if isinstance(obj, Portal)]
assert len(portals) == 2
def test_multiple_spawns(tmp_path: Path) -> None:
"""Test importing multiple spawn rules."""
yaml_content = """
name: multi_spawn
width: 5
height: 5
terrain:
rows:
- "....."
- "....."
- "....."
- "....."
- "....."
spawns:
- mob: goblin
max_count: 2
- mob: orc
max_count: 1
respawn_seconds: 600
"""
yaml_file = tmp_path / "multi_spawn.yaml"
yaml_file.write_text(yaml_content)
from scripts.import_map import import_map
output_file = import_map(yaml_file, tmp_path)
zone = load_zone(output_file)
assert len(zone.spawn_rules) == 2
assert zone.spawn_rules[0].mob == "goblin"
assert zone.spawn_rules[0].max_count == 2
assert zone.spawn_rules[1].mob == "orc"
assert zone.spawn_rules[1].respawn_seconds == 600