Test suite modernization

This commit is contained in:
John McCardle 2026-02-09 08:15:18 -05:00
commit 52fdfd0347
141 changed files with 9947 additions and 4665 deletions

View file

@ -0,0 +1,470 @@
"""Verify code snippets from Phase D batch 3 wiki updates."""
import mcrfpy
import sys
passes = 0
fails = 0
def check(name, fn):
global passes, fails
try:
fn()
passes += 1
print(f" [OK] {name}")
except Exception as e:
fails += 1
print(f" [FAIL] {name}: {e}")
# ===================================================================
print("=== PROCEDURAL GENERATION ===")
# ===================================================================
def test_pg_bsp_basic():
"""BSP dungeon generation pattern"""
grid = mcrfpy.Grid(grid_size=(50, 50), pos=(0, 0), size=(400, 400))
# Set cells walkable (carve a room)
for x in range(10, 20):
for y in range(10, 20):
cell = grid.at(x, y)
cell.walkable = True
cell.transparent = True
# Verify
assert grid.at(15, 15).walkable == True
assert grid.at(0, 0).walkable == False
check("PG: BSP basic grid setup", test_pg_bsp_basic)
def test_pg_cell_properties():
"""Cell property access patterns"""
grid = mcrfpy.Grid(grid_size=(20, 20), pos=(0, 0), size=(320, 320))
cell = grid.at(5, 5)
# Test walkable
cell.walkable = True
assert cell.walkable == True
cell.walkable = False
assert cell.walkable == False
# Test transparent
cell.transparent = True
assert cell.transparent == True
cell.transparent = False
assert cell.transparent == False
check("PG: cell properties", test_pg_cell_properties)
def test_pg_entity_placement():
"""Entity placement in generated rooms"""
import random
grid = mcrfpy.Grid(grid_size=(30, 30), pos=(0, 0), size=(400, 400))
# Place entities
for i in range(5):
e = mcrfpy.Entity(grid_pos=(10 + i, 10), sprite_index=i)
grid.entities.append(e)
assert len(grid.entities) == 5
check("PG: entity placement", test_pg_entity_placement)
def test_pg_scene_setup():
"""Scene setup for procgen"""
scene = mcrfpy.Scene("pg_test")
grid = mcrfpy.Grid(grid_size=(50, 50), pos=(0, 0), size=(400, 400))
scene.children.append(grid)
player = mcrfpy.Entity(grid_pos=(25, 25), sprite_index=1)
grid.entities.append(player)
check("PG: scene setup", test_pg_scene_setup)
def test_pg_timer_generation():
"""Timer-based incremental generation"""
step_count = [0]
def generate_step(timer, runtime):
step_count[0] += 1
if step_count[0] >= 3:
timer.stop()
t = mcrfpy.Timer("pg_gen", generate_step, 100)
# Each step() call can fire at most one timer event
for _ in range(5):
mcrfpy.step(0.11)
assert step_count[0] >= 3, f"Expected >= 3 fires, got {step_count[0]}"
t.stop()
check("PG: timer generation", test_pg_timer_generation)
def test_pg_grid_size():
"""Grid size access"""
grid = mcrfpy.Grid(grid_size=(40, 30), pos=(0, 0), size=(400, 300))
gs = grid.grid_size
assert gs[0] == 40
assert gs[1] == 30
check("PG: grid_size property", test_pg_grid_size)
# ===================================================================
print("\n=== GRID RENDERING PIPELINE ===")
# ===================================================================
def test_grp_layer_creation():
"""Layer creation with standalone objects"""
grid = mcrfpy.Grid(grid_size=(20, 20), pos=(0, 0), size=(320, 320), layers=[])
# Create layers as standalone objects
bg = mcrfpy.ColorLayer(name="background", z_index=-2)
grid.add_layer(bg)
# Overlay above entities
overlay = mcrfpy.ColorLayer(name="overlay", z_index=1)
grid.add_layer(overlay)
# Verify layers exist
assert grid.layer("background") is not None
assert grid.layer("overlay") is not None
check("GRP: layer creation", test_grp_layer_creation)
def test_grp_layer_operations():
"""Layer set/at/fill operations"""
grid = mcrfpy.Grid(grid_size=(10, 10), pos=(0, 0), size=(160, 160), layers=[])
cl = mcrfpy.ColorLayer(name="colors", z_index=-1)
grid.add_layer(cl)
# Fill
cl.fill(mcrfpy.Color(0, 0, 0, 255))
# Set individual cell
cl.set((5, 5), mcrfpy.Color(255, 0, 0, 255))
# Read back
c = cl.at((5, 5))
assert c.r == 255
check("GRP: layer operations", test_grp_layer_operations)
def test_grp_tile_layer():
"""TileLayer creation"""
grid = mcrfpy.Grid(grid_size=(10, 10), pos=(0, 0), size=(160, 160), layers=[])
tl = mcrfpy.TileLayer(name="tiles", z_index=-1)
grid.add_layer(tl)
assert grid.layer("tiles") is not None
check("GRP: TileLayer creation", test_grp_tile_layer)
def test_grp_z_index():
"""Z-index layer ordering"""
grid = mcrfpy.Grid(grid_size=(10, 10), pos=(0, 0), size=(160, 160), layers=[])
l1 = mcrfpy.ColorLayer(name="below", z_index=-2)
l2 = mcrfpy.ColorLayer(name="above", z_index=1)
grid.add_layer(l1)
grid.add_layer(l2)
below = grid.layer("below")
above = grid.layer("above")
assert below.z_index == -2
assert above.z_index == 1
check("GRP: z-index ordering", test_grp_z_index)
def test_grp_fog_overlay():
"""Fog overlay pattern with layer"""
grid = mcrfpy.Grid(grid_size=(20, 20), pos=(0, 0), size=(320, 320), layers=[])
fog = mcrfpy.ColorLayer(name="fog", z_index=1)
grid.add_layer(fog)
fog.fill(mcrfpy.Color(0, 0, 0, 192))
# Make all cells transparent for FOV
for x in range(20):
for y in range(20):
grid.at(x, y).transparent = True
grid.at(x, y).walkable = True
# Compute FOV and reveal
grid.compute_fov((10, 10), radius=8)
for x in range(20):
for y in range(20):
if grid.is_in_fov((x, y)):
fog.set((x, y), mcrfpy.Color(0, 0, 0, 0))
# Origin should be revealed
c = fog.at((10, 10))
assert c.a == 0
check("GRP: fog overlay", test_grp_fog_overlay)
def test_grp_grid_properties():
"""Grid rendering properties"""
grid = mcrfpy.Grid(grid_size=(20, 20), pos=(0, 0), size=(320, 320))
# Check zoom property exists
assert hasattr(grid, 'zoom')
# Check center properties
assert hasattr(grid, 'center')
check("GRP: grid properties", test_grp_grid_properties)
# ===================================================================
print("\n=== GRID TCOD INTEGRATION ===")
# ===================================================================
def test_tcod_fov():
"""FOV computation with tuple args"""
grid = mcrfpy.Grid(grid_size=(30, 30), pos=(0, 0), size=(400, 400))
for x in range(30):
for y in range(30):
grid.at(x, y).transparent = True
grid.at(x, y).walkable = True
# Add wall
grid.at(15, 10).transparent = False
grid.at(15, 10).walkable = False
# Compute FOV
grid.compute_fov((10, 10), radius=10)
# Origin should be visible
assert grid.is_in_fov((10, 10))
# Behind wall might not be visible
# (depends on exact algorithm, just check API works)
grid.is_in_fov((20, 10)) # Just verify no crash
check("TCOD: FOV computation", test_tcod_fov)
def test_tcod_pathfinding():
"""A* pathfinding with AStarPath object"""
grid = mcrfpy.Grid(grid_size=(30, 30), pos=(0, 0), size=(400, 400))
for x in range(30):
for y in range(30):
grid.at(x, y).walkable = True
# Find path
path = grid.find_path((5, 5), (25, 25))
assert path is not None
assert len(path) > 0
# Walk the path
step = path.walk()
assert step is not None
# Check properties
assert path.origin is not None
assert path.destination is not None
assert path.remaining >= 0
check("TCOD: A* pathfinding", test_tcod_pathfinding)
def test_tcod_dijkstra():
"""Dijkstra map with DijkstraMap object"""
grid = mcrfpy.Grid(grid_size=(30, 30), pos=(0, 0), size=(400, 400))
for x in range(30):
for y in range(30):
grid.at(x, y).walkable = True
dm = grid.get_dijkstra_map((15, 15))
# Get distance
d = dm.distance((0, 0))
assert d > 0
# Get path
p = dm.path_from((0, 0))
assert len(p) > 0
# Get next step
s = dm.step_from((0, 0))
assert s is not None
check("TCOD: Dijkstra map", test_tcod_dijkstra)
def test_tcod_perspective():
"""Grid perspective assignment"""
grid = mcrfpy.Grid(grid_size=(20, 20), pos=(0, 0), size=(320, 320))
player = mcrfpy.Entity(grid_pos=(10, 10), sprite_index=0)
grid.entities.append(player)
# Set perspective
grid.perspective = player
assert grid.perspective is not None
check("TCOD: perspective", test_tcod_perspective)
def test_tcod_dynamic_obstacle():
"""Dynamic obstacle pattern"""
grid = mcrfpy.Grid(grid_size=(20, 20), pos=(0, 0), size=(320, 320))
for x in range(20):
for y in range(20):
grid.at(x, y).walkable = True
# Open door pattern
door = grid.at(10, 10)
door.walkable = False
door.transparent = False
# Verify path around door
path = grid.find_path((5, 10), (15, 10))
assert path is not None # Should find path around
# Open door
door.walkable = True
door.transparent = True
# Path should now go through
path2 = grid.find_path((5, 10), (15, 10))
assert path2 is not None
# Direct path should be shorter
assert len(path2) <= len(path)
check("TCOD: dynamic obstacle", test_tcod_dynamic_obstacle)
# ===================================================================
print("\n=== PERFORMANCE PATTERNS ===")
# ===================================================================
def test_perf_benchmark_api():
"""Check benchmark API exists"""
assert hasattr(mcrfpy, 'start_benchmark') or True # May not exist
# Just check step works for headless benchmarking
dt = mcrfpy.step(0.016)
assert dt is not None
check("PERF: step-based benchmarking", test_perf_benchmark_api)
def test_perf_timer_benchmark():
"""Timer-based benchmarking pattern"""
frame_times = []
def measure(timer, runtime):
frame_times.append(runtime)
if len(frame_times) >= 5:
timer.stop()
t = mcrfpy.Timer("perf_bench", measure, 50)
mcrfpy.step(0.3) # Run several frames
t.stop()
assert len(frame_times) > 0
check("PERF: timer benchmark", test_perf_timer_benchmark)
# ===================================================================
print("\n=== PYTHON BINDING LAYER PATTERNS ===")
# ===================================================================
def test_pbl_grid_constructor():
"""Modern grid constructor"""
grid = mcrfpy.Grid(grid_size=(10, 10), pos=(0, 0), size=(160, 160))
gs = grid.grid_size
assert gs[0] == 10
assert gs[1] == 10
check("PBL: Grid constructor", test_pbl_grid_constructor)
def test_pbl_entity_constructor():
"""Modern entity constructor"""
e = mcrfpy.Entity(grid_pos=(5, 5), sprite_index=42)
assert e.grid_x == 5
assert e.grid_y == 5
# sprite_index is set
assert e.sprite_index == 42
check("PBL: Entity constructor", test_pbl_entity_constructor)
def test_pbl_frame_constructor():
"""Frame constructor with keywords"""
f = mcrfpy.Frame(pos=(100, 200), size=(300, 150))
assert f.x == 100
assert f.y == 200
assert f.w == 300
assert f.h == 150
check("PBL: Frame constructor", test_pbl_frame_constructor)
def test_pbl_sprite_constructor():
"""Sprite constructor"""
s = mcrfpy.Sprite(x=10, y=20, sprite_index=5)
assert s.x == 10
assert s.y == 20
check("PBL: Sprite constructor", test_pbl_sprite_constructor)
def test_pbl_caption_constructor():
"""Caption constructor"""
c = mcrfpy.Caption(text="Hello", pos=(50, 60))
assert c.text == "Hello"
assert c.x == 50
check("PBL: Caption constructor", test_pbl_caption_constructor)
def test_pbl_color():
"""Color creation"""
c = mcrfpy.Color(255, 128, 0, 200)
assert c.r == 255
assert c.g == 128
assert c.b == 0
assert c.a == 200
check("PBL: Color object", test_pbl_color)
def test_pbl_scene_api():
"""Scene API pattern"""
scene = mcrfpy.Scene("pbl_test")
f = mcrfpy.Frame(pos=(0, 0), size=(100, 100))
scene.children.append(f)
assert len(scene.children) >= 1
check("PBL: Scene API", test_pbl_scene_api)
# Check what benchmark API exists
def test_check_benchmark_api():
"""Check which benchmark methods exist"""
has_start = hasattr(mcrfpy, 'start_benchmark')
has_end = hasattr(mcrfpy, 'end_benchmark')
has_log = hasattr(mcrfpy, 'log_benchmark')
print(f" start_benchmark: {has_start}, end_benchmark: {has_end}, log_benchmark: {has_log}")
# Also check for sync methods on grid
grid = mcrfpy.Grid(grid_size=(10, 10), pos=(0, 0), size=(160, 160))
has_sync = hasattr(grid, 'sync_tcod_map')
has_sync_cell = hasattr(grid, 'sync_tcod_cell')
print(f" sync_tcod_map: {has_sync}, sync_tcod_cell: {has_sync_cell}")
# Check for FOV algorithm constants
has_fov_basic = hasattr(mcrfpy, 'FOV_BASIC')
print(f" FOV_BASIC constant: {has_fov_basic}")
# Check cell.tilesprite
cell = grid.at(0, 0)
has_tilesprite = hasattr(cell, 'tilesprite')
has_sprite_index = hasattr(cell, 'sprite_index')
has_tile_index = hasattr(cell, 'tile_index')
print(f" cell.tilesprite: {has_tilesprite}, cell.sprite_index: {has_sprite_index}, cell.tile_index: {has_tile_index}")
# Check cell color property
has_color = hasattr(cell, 'color')
has_fill_color = hasattr(cell, 'fill_color')
print(f" cell.color: {has_color}, cell.fill_color: {has_fill_color}")
# Check entities_in_radius
has_eir = hasattr(grid, 'entities_in_radius')
print(f" entities_in_radius: {has_eir}")
# List all grid cell (GridPoint) attributes
cell_attrs = [a for a in dir(cell) if not a.startswith('_')]
print(f" GridPoint attrs: {cell_attrs}")
check("API: check available methods", test_check_benchmark_api)
# ===================================================================
print("\n" + "=" * 60)
print(f"PHASE D3 VERIFICATION: {passes} passed, {fails} failed")
print("=" * 60)
if fails:
sys.exit(1)
else:
sys.exit(0)