McRogueFace/tests/unit/ldtk_apply_test.py

183 lines
5.7 KiB
Python
Raw Normal View History

2026-02-07 11:30:32 -05:00
"""Unit tests for LDtk auto-rule apply (resolve + write to TileLayer)."""
import mcrfpy
import sys
def test_apply_basic():
"""Test applying rules to a TileLayer."""
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
rs = proj.ruleset("Terrain")
ts = proj.tileset("Test_Tileset")
texture = ts.to_texture()
# Create DiscreteMap
dm = mcrfpy.DiscreteMap((5, 5), fill=0)
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)
elif x == 2 and y == 2:
dm.set(x, y, 3)
else:
dm.set(x, y, 2)
# Create TileLayer and apply
layer = mcrfpy.TileLayer(name="terrain", texture=texture, grid_size=(5, 5))
rs.apply(dm, layer, seed=0)
# Verify some tiles were written
wall_tile = layer.at(0, 0)
assert wall_tile == 0, f"Expected wall tile 0 at (0,0), got {wall_tile}"
floor_tile = layer.at(1, 1)
assert floor_tile >= 0, f"Expected floor tile at (1,1), got {floor_tile}"
# Empty cells (water, value=3) should still be -1 (no rule matches water)
water_tile = layer.at(2, 2)
assert water_tile == -1, f"Expected -1 at water (2,2), got {water_tile}"
print(f" applied: wall={wall_tile}, floor={floor_tile}, water={water_tile}")
def test_apply_preserves_unmatched():
"""Test that unmatched cells retain their original value."""
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
rs = proj.ruleset("Terrain")
ts = proj.tileset("Test_Tileset")
texture = ts.to_texture()
# Pre-fill layer with a sentinel value
layer = mcrfpy.TileLayer(name="test", texture=texture, grid_size=(3, 3))
layer.fill(99)
# Create empty map - no rules will match
dm = mcrfpy.DiscreteMap((3, 3), fill=0)
rs.apply(dm, layer, seed=0)
# All cells should still be 99 (no rules matched)
for y in range(3):
for x in range(3):
val = layer.at(x, y)
assert val == 99, f"Expected 99 at ({x},{y}), got {val}"
print(" unmatched cells preserved: OK")
def test_apply_type_errors():
"""Test that apply raises TypeError for wrong argument types."""
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
rs = proj.ruleset("Terrain")
# Wrong first argument type
try:
rs.apply("not_a_dmap", None, seed=0)
assert False, "Should have raised TypeError"
except TypeError:
pass
# Wrong second argument type
dm = mcrfpy.DiscreteMap((3, 3))
try:
rs.apply(dm, "not_a_layer", seed=0)
assert False, "Should have raised TypeError"
except TypeError:
pass
print(" type errors raised correctly: OK")
def test_apply_clipping():
"""Test that apply clips to the smaller of map/layer dimensions."""
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
rs = proj.ruleset("Terrain")
ts = proj.tileset("Test_Tileset")
texture = ts.to_texture()
# DiscreteMap larger than TileLayer
dm = mcrfpy.DiscreteMap((10, 10), fill=1)
layer = mcrfpy.TileLayer(name="small", texture=texture, grid_size=(3, 3))
layer.fill(-1)
rs.apply(dm, layer, seed=0)
# Layer should have tiles written only within its bounds
for y in range(3):
for x in range(3):
val = layer.at(x, y)
assert val >= 0, f"Expected tile at ({x},{y}), got {val}"
print(" clipping (large map, small layer): OK")
# DiscreteMap smaller than TileLayer
dm2 = mcrfpy.DiscreteMap((2, 2), fill=1)
layer2 = mcrfpy.TileLayer(name="big", texture=texture, grid_size=(5, 5))
layer2.fill(88)
rs.apply(dm2, layer2, seed=0)
# Only (0,0)-(1,1) should be overwritten
for y in range(2):
for x in range(2):
val = layer2.at(x, y)
assert val >= 0, f"Expected tile at ({x},{y}), got {val}"
# (3,3) should still be the fill value
assert layer2.at(3, 3) == 88, f"Expected 88 at (3,3), got {layer2.at(3, 3)}"
print(" clipping (small map, large layer): OK")
def test_resolve_type_error():
"""Test that resolve raises TypeError for wrong argument."""
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
rs = proj.ruleset("Terrain")
try:
rs.resolve("not_a_dmap", seed=0)
assert False, "Should have raised TypeError"
except TypeError:
pass
print(" resolve TypeError: OK")
def test_precomputed_tiles():
"""Test loading pre-computed auto-layer tiles from a level."""
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
ts = proj.tileset("Test_Tileset")
texture = ts.to_texture()
level = proj.level("Level_0")
layer_info = level["layers"][0]
# Create TileLayer and write pre-computed tiles
layer = mcrfpy.TileLayer(name="precomp", texture=texture, grid_size=(5, 5))
layer.fill(-1)
for tile in layer_info["auto_tiles"]:
x, y = tile["x"], tile["y"]
if 0 <= x < 5 and 0 <= y < 5:
layer.set((x, y), tile["tile_id"])
# Verify some tiles were written
assert layer.at(0, 0) == 0, f"Expected tile 0 at (0,0), got {layer.at(0, 0)}"
print(f" precomputed tiles loaded: first = {layer.at(0, 0)}")
# Run tests
tests = [
test_apply_basic,
test_apply_preserves_unmatched,
test_apply_type_errors,
test_apply_clipping,
test_resolve_type_error,
test_precomputed_tiles,
]
passed = 0
failed = 0
print("=== LDtk Apply 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)