"""Tests for zone export to TOML files.""" import pathlib import tempfile from mudlib.export import export_zone, export_zone_to_file from mudlib.portal import Portal from mudlib.zone import SpawnRule, Zone from mudlib.zones import load_zone def test_export_basic_zone(): """Export a simple zone and verify TOML output has correct fields.""" zone = Zone( name="test_zone", width=4, height=3, toroidal=False, terrain=[ ["#", "#", "#", "#"], ["#", ".", ".", "#"], ["#", "#", "#", "#"], ], impassable={"#"}, spawn_x=0, spawn_y=0, ) # Set description as an attribute (zones loaded from TOML have this) zone.description = "a test zone" toml_str = export_zone(zone) # Verify basic fields are present assert 'name = "test_zone"' in toml_str assert 'description = "a test zone"' in toml_str assert "width = 4" in toml_str assert "height = 3" in toml_str assert "toroidal = false" in toml_str assert "spawn_x = 0" in toml_str assert "spawn_y = 0" in toml_str # Verify terrain section assert "[terrain]" in toml_str assert '"####"' in toml_str assert '"#..#"' in toml_str # Verify impassable tiles assert "[terrain.impassable]" in toml_str assert '"#"' in toml_str def test_export_zone_round_trip(): """Export a zone, load it back, verify it matches the original.""" original = Zone( name="round_trip", width=5, height=4, toroidal=True, terrain=[ [".", ".", ".", ".", "."], [".", "#", "#", "#", "."], [".", "#", ".", "#", "."], [".", ".", ".", ".", "."], ], impassable={"#"}, spawn_x=2, spawn_y=1, ) original.description = "round trip test" toml_str = export_zone(original) # Write to temp file and load back with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f: f.write(toml_str) temp_path = pathlib.Path(f.name) try: loaded = load_zone(temp_path) # Verify all fields match assert loaded.name == original.name assert loaded.description == original.description assert loaded.width == original.width assert loaded.height == original.height assert loaded.toroidal == original.toroidal assert loaded.spawn_x == original.spawn_x assert loaded.spawn_y == original.spawn_y assert loaded.terrain == original.terrain assert loaded.impassable == original.impassable finally: temp_path.unlink() def test_export_zone_with_portals(): """Zone with Portal objects exports [[portals]] sections.""" zone = Zone( name="portal_zone", width=10, height=10, terrain=[["." for _ in range(10)] for _ in range(10)], impassable=set(), ) zone.description = "a zone with portals" # Add portals Portal( name="tavern door", location=zone, x=5, y=3, target_zone="tavern", target_x=1, target_y=1, ) Portal( name="forest path", aliases=["path", "entrance"], location=zone, x=2, y=7, target_zone="forest", target_x=10, target_y=5, ) toml_str = export_zone(zone) # Verify portals section exists assert "[[portals]]" in toml_str # Verify first portal assert "x = 5" in toml_str assert "y = 3" in toml_str assert 'target = "tavern:1,1"' in toml_str assert 'label = "tavern door"' in toml_str # Verify second portal assert "x = 2" in toml_str assert "y = 7" in toml_str assert 'target = "forest:10,5"' in toml_str assert 'label = "forest path"' in toml_str assert 'aliases = ["path", "entrance"]' in toml_str def test_export_zone_with_portals_round_trip(): """Export a zone with portals, load it back, verify portals match.""" zone = Zone( name="portal_round_trip", width=8, height=6, toroidal=False, terrain=[["." for _ in range(8)] for _ in range(6)], impassable=set(), spawn_x=0, spawn_y=0, ) zone.description = "portal round trip test" # Add portals Portal( name="tavern door", location=zone, x=5, y=3, target_zone="tavern", target_x=1, target_y=2, ) Portal( name="forest path", aliases=["path"], location=zone, x=2, y=4, target_zone="forest", target_x=10, target_y=5, ) toml_str = export_zone(zone) # Write to temp file and load back with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f: f.write(toml_str) temp_path = pathlib.Path(f.name) try: loaded = load_zone(temp_path) # Verify basic zone fields assert loaded.name == zone.name assert loaded.description == zone.description assert loaded.width == zone.width assert loaded.height == zone.height # Verify portals were loaded correctly portals = [obj for obj in loaded._contents if isinstance(obj, Portal)] assert len(portals) == 2 # Sort by y coordinate for consistent ordering portals.sort(key=lambda p: (p.y, p.x)) # Verify first portal (tavern door at 5,3) assert portals[0].name == "tavern door" assert portals[0].x == 5 assert portals[0].y == 3 assert portals[0].target_zone == "tavern" assert portals[0].target_x == 1 assert portals[0].target_y == 2 # Verify second portal (forest path at 2,4) assert portals[1].name == "forest path" assert portals[1].x == 2 assert portals[1].y == 4 assert portals[1].target_zone == "forest" assert portals[1].target_x == 10 assert portals[1].target_y == 5 assert "path" in portals[1].aliases finally: temp_path.unlink() def test_export_zone_with_spawn_point(): """spawn_x/spawn_y are in the output.""" zone = Zone( name="spawn_zone", width=10, height=10, terrain=[["." for _ in range(10)] for _ in range(10)], spawn_x=5, spawn_y=7, ) zone.description = "a zone with spawn point" toml_str = export_zone(zone) assert "spawn_x = 5" in toml_str assert "spawn_y = 7" in toml_str def test_export_zone_to_file(): """Write TOML to a file, load it back.""" zone = Zone( name="file_zone", width=3, height=3, terrain=[ ["#", "#", "#"], ["#", ".", "#"], ["#", "#", "#"], ], impassable={"#"}, ) zone.description = "exported to file" with tempfile.TemporaryDirectory() as tmpdir: output_path = pathlib.Path(tmpdir) / "test_zone.toml" export_zone_to_file(zone, output_path) # Verify file exists assert output_path.exists() # Load it back loaded = load_zone(output_path) assert loaded.name == zone.name assert loaded.width == zone.width assert loaded.height == zone.height assert loaded.terrain == zone.terrain def test_export_zone_with_ambient_messages(): """Zone with ambient messages exports [ambient] section.""" zone = Zone( name="ambient_zone", width=5, height=5, terrain=[["." for _ in range(5)] for _ in range(5)], ambient_messages=[ "Birds chirp overhead.", "A cool breeze passes by.", "Leaves rustle in the distance.", ], ambient_interval=90, ) zone.description = "a zone with ambient messages" toml_str = export_zone(zone) # Verify ambient section assert "[ambient]" in toml_str assert "interval = 90" in toml_str assert "Birds chirp overhead." in toml_str assert "A cool breeze passes by." in toml_str assert "Leaves rustle in the distance." in toml_str def test_export_zone_with_spawn_rules(): """Zone with spawn rules exports [[spawns]] sections.""" zone = Zone( name="spawn_zone", width=10, height=10, terrain=[["." for _ in range(10)] for _ in range(10)], spawn_rules=[ SpawnRule(mob="squirrel", max_count=2, respawn_seconds=180), SpawnRule(mob="crow", max_count=1, respawn_seconds=300), ], ) toml_str = export_zone(zone) # Verify spawns sections assert "[[spawns]]" in toml_str assert 'mob = "squirrel"' in toml_str assert "max_count = 2" in toml_str assert "respawn_seconds = 180" in toml_str assert 'mob = "crow"' in toml_str assert "max_count = 1" in toml_str assert "respawn_seconds = 300" in toml_str def test_export_safe_zone(): """Export includes safe = true when zone is safe.""" terrain = [["." for _ in range(3)] for _ in range(3)] zone = Zone( name="sanctuary", width=3, height=3, terrain=terrain, safe=True, ) result = export_zone(zone) assert "safe = true" in result def test_export_unsafe_zone_omits_safe(): """Export omits safe field when zone is not safe (default).""" terrain = [["." for _ in range(3)] for _ in range(3)] zone = Zone( name="wilderness", width=3, height=3, terrain=terrain, safe=False, ) result = export_zone(zone) assert "safe" not in result def test_export_spawn_with_home_region(): """Export includes home_region on spawn rules when present.""" terrain = [["." for _ in range(5)] for _ in range(5)] zone = Zone( name="forest", width=5, height=5, terrain=terrain, spawn_rules=[ SpawnRule( mob="squirrel", max_count=2, respawn_seconds=180, home_region={"x": [5, 15], "y": [3, 10]}, ) ], ) result = export_zone(zone) assert "home_region" in result assert "x = [5, 15]" in result assert "y = [3, 10]" in result def test_export_spawn_without_home_region(): """Export omits home_region when not set.""" terrain = [["." for _ in range(5)] for _ in range(5)] zone = Zone( name="forest", width=5, height=5, terrain=terrain, spawn_rules=[SpawnRule(mob="goblin", max_count=1)], ) result = export_zone(zone) assert "home_region" not in result def test_export_safe_zone_round_trip(): """Safe zone survives export/import round-trip.""" terrain = [["." for _ in range(3)] for _ in range(3)] zone = Zone( name="temple", width=3, height=3, terrain=terrain, safe=True, ) with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f: f.write(export_zone(zone)) temp_path = pathlib.Path(f.name) try: reloaded = load_zone(temp_path) assert reloaded.safe is True finally: temp_path.unlink() def test_export_home_region_round_trip(): """Home region on spawn rules survives export/import round-trip.""" terrain = [["." for _ in range(5)] for _ in range(5)] zone = Zone( name="woods", width=5, height=5, terrain=terrain, spawn_rules=[ SpawnRule( mob="deer", max_count=3, respawn_seconds=120, home_region={"x": [1, 4], "y": [1, 4]}, ) ], ) with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f: f.write(export_zone(zone)) temp_path = pathlib.Path(f.name) try: reloaded = load_zone(temp_path) assert len(reloaded.spawn_rules) == 1 rule = reloaded.spawn_rules[0] assert rule.home_region == {"x": [1, 4], "y": [1, 4]} finally: temp_path.unlink()