McRogueFace/tests/unit/ldtk_resolve_test.py

146 lines
5.3 KiB
Python
Raw Permalink Normal View History

2026-02-07 11:30:32 -05:00
"""Unit tests for LDtk auto-rule resolution."""
import mcrfpy
import sys
def test_basic_resolve():
"""Test resolving a simple IntGrid against auto-rules."""
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
rs = proj.ruleset("Terrain")
# Create a DiscreteMap matching the test fixture
dm = mcrfpy.DiscreteMap((5, 5), fill=0)
# Fill with the same pattern as test_project.ldtk Level_0:
# 1 1 1 1 1
# 1 2 2 2 1
# 1 2 3 2 1
# 1 2 2 2 1
# 1 1 1 1 1
for y in range(5):
for x in range(5):
if x == 0 or x == 4 or y == 0 or y == 4:
dm.set(x, y, 1) # wall
elif x == 2 and y == 2:
dm.set(x, y, 3) # water
else:
dm.set(x, y, 2) # floor
tiles = rs.resolve(dm, seed=0)
assert isinstance(tiles, list), f"Expected list, got {type(tiles)}"
assert len(tiles) == 25, f"Expected 25 tiles, got {len(tiles)}"
print(f" resolved: {tiles}")
# Wall cells (value=1) should have tile_id 0 (from rule 51 matching pattern center=1)
assert tiles[0] >= 0, f"Expected wall tile at (0,0), got {tiles[0]}"
# Floor cells (value=2) should match floor rule (rule 61, tile_id 2 or 3)
assert tiles[6] >= 0, f"Expected floor tile at (1,1), got {tiles[6]}"
print(" wall and floor cells matched rules: OK")
def test_resolve_with_seed():
"""Test that different seeds produce deterministic but different results for multi-tile rules."""
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
rs = proj.ruleset("Terrain")
dm = mcrfpy.DiscreteMap((5, 5), fill=2) # All floor
tiles_a = rs.resolve(dm, seed=0)
tiles_b = rs.resolve(dm, seed=0)
tiles_c = rs.resolve(dm, seed=42)
# Same seed = same result
assert tiles_a == tiles_b, "Same seed should produce same result"
print(" deterministic with same seed: OK")
# Different seed may produce different tile picks (floor rule has 2 alternatives)
# Not guaranteed to differ for all cells, but we test determinism
tiles_d = rs.resolve(dm, seed=42)
assert tiles_c == tiles_d, "Same seed should produce same result"
print(" deterministic with different seed: OK")
def test_resolve_empty():
"""Test resolving an all-empty grid (value 0 = empty)."""
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
rs = proj.ruleset("Terrain")
dm = mcrfpy.DiscreteMap((3, 3), fill=0)
tiles = rs.resolve(dm, seed=0)
assert len(tiles) == 9, f"Expected 9 tiles, got {len(tiles)}"
# All empty - no rules should match (rules match value 1 or 2)
for i, t in enumerate(tiles):
assert t == -1, f"Expected -1 at index {i}, got {t}"
print(" empty grid: all tiles -1: OK")
def test_pattern_negation():
"""Test that negative pattern values work (must NOT match)."""
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
rs = proj.ruleset("Terrain")
# Rule 52 has pattern: [0, -1, 0, 0, 1, 0, 0, 0, 0]
# Center must be 1 (wall), top neighbor must NOT be 1
# Create a 3x3 grid with wall center and non-wall top
dm = mcrfpy.DiscreteMap((3, 3), fill=0)
dm.set(1, 1, 1) # center = wall
dm.set(1, 0, 2) # top = floor (not wall)
tiles = rs.resolve(dm, seed=0)
# The center cell should match rule 52 (wall with non-wall top)
# Rule 52 gives tile_id 1 (from tileRectsIds [16,0] = column 1, row 0 = tile 1)
center = tiles[4] # (1,1) = index 4 in 3x3
print(f" negation pattern: center tile = {center}")
# It should match either rule 51 (generic wall) or rule 52 (wall with non-wall top)
assert center >= 0, f"Expected match at center, got {center}"
print(" pattern negation test: OK")
def test_resolve_dimensions():
"""Test resolve works with different grid dimensions."""
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
rs = proj.ruleset("Terrain")
for w, h in [(1, 1), (3, 3), (10, 10), (1, 20), (20, 1)]:
dm = mcrfpy.DiscreteMap((w, h), fill=1)
tiles = rs.resolve(dm, seed=0)
assert len(tiles) == w * h, f"Expected {w*h} tiles for {w}x{h}, got {len(tiles)}"
print(" various dimensions: OK")
def test_break_on_match():
"""Test that breakOnMatch prevents later rules from overwriting."""
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
rs = proj.ruleset("Terrain")
# Create a grid where rule 51 (generic wall) should match
# Rule 51 has breakOnMatch=true, so rule 52 should not override it
dm = mcrfpy.DiscreteMap((3, 3), fill=1) # All walls
tiles = rs.resolve(dm, seed=0)
# All cells should be tile 0 (from rule 51)
center = tiles[4]
assert center == 0, f"Expected tile 0 from rule 51, got {center}"
print(f" break on match: center = {center}: OK")
# Run tests
tests = [
test_basic_resolve,
test_resolve_with_seed,
test_resolve_empty,
test_pattern_negation,
test_resolve_dimensions,
test_break_on_match,
]
passed = 0
failed = 0
print("=== LDtk Resolve Tests ===")
for test in tests:
name = test.__name__
try:
print(f"[TEST] {name}...")
test()
passed += 1
print(f" PASS")
except Exception as e:
failed += 1
print(f" FAIL: {e}")
print(f"\n=== Results: {passed} passed, {failed} failed ===")
if failed > 0:
sys.exit(1)
sys.exit(0)