Test suite modernization
This commit is contained in:
parent
0969f7c2f6
commit
52fdfd0347
141 changed files with 9947 additions and 4665 deletions
408
tests/wiki_phase_d2_verify.py
Normal file
408
tests/wiki_phase_d2_verify.py
Normal file
|
|
@ -0,0 +1,408 @@
|
|||
"""Verify code snippets from Phase D batch 2 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("=== AI AND PATHFINDING ===")
|
||||
# ===================================================================
|
||||
|
||||
def test_aip_fov_basic():
|
||||
"""Basic FOV setup"""
|
||||
grid = mcrfpy.Grid(grid_size=(50, 50), pos=(0, 0), size=(400, 400))
|
||||
for x in range(50):
|
||||
for y in range(50):
|
||||
grid.at(x, y).transparent = True
|
||||
grid.at(x, y).walkable = True
|
||||
# Set some walls
|
||||
grid.at(10, 10).transparent = False
|
||||
grid.at(10, 10).walkable = False
|
||||
# Compute FOV
|
||||
grid.compute_fov((25, 25), radius=10)
|
||||
assert grid.is_in_fov((25, 25)) # Origin visible
|
||||
assert not grid.is_in_fov((0, 0)) # Far away not visible
|
||||
|
||||
check("AIP: basic FOV", test_aip_fov_basic)
|
||||
|
||||
def test_aip_perspective():
|
||||
"""Perspective system"""
|
||||
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)
|
||||
grid.perspective = player
|
||||
assert grid.perspective is not None
|
||||
|
||||
check("AIP: perspective", test_aip_perspective)
|
||||
|
||||
def test_aip_fog_of_war():
|
||||
"""Fog of war pattern"""
|
||||
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, 255))
|
||||
|
||||
for x in range(20):
|
||||
for y in range(20):
|
||||
grid.at(x, y).transparent = True
|
||||
grid.at(x, y).walkable = True
|
||||
|
||||
player = mcrfpy.Entity(grid_pos=(10, 10), sprite_index=0)
|
||||
grid.entities.append(player)
|
||||
|
||||
# Compute FOV and reveal fog
|
||||
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))
|
||||
|
||||
# Check fog revealed at origin
|
||||
c = fog.at((10, 10))
|
||||
assert c.a == 0 # Revealed
|
||||
|
||||
check("AIP: fog of war", test_aip_fog_of_war)
|
||||
|
||||
def test_aip_astar():
|
||||
"""A* pathfinding via grid"""
|
||||
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
|
||||
|
||||
path = grid.find_path((10, 10), (20, 20))
|
||||
assert path is not None
|
||||
assert len(path) > 0
|
||||
step = path.walk()
|
||||
assert step is not None
|
||||
assert path.remaining >= 0
|
||||
assert path.origin is not None
|
||||
assert path.destination is not None
|
||||
|
||||
check("AIP: A* pathfinding", test_aip_astar)
|
||||
|
||||
def test_aip_dijkstra():
|
||||
"""Dijkstra map"""
|
||||
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))
|
||||
d = dm.distance((0, 0))
|
||||
assert d > 0
|
||||
p = dm.path_from((0, 0))
|
||||
assert len(p) > 0
|
||||
s = dm.step_from((0, 0))
|
||||
assert s is not None
|
||||
|
||||
check("AIP: Dijkstra map", test_aip_dijkstra)
|
||||
|
||||
def test_aip_chase_pattern():
|
||||
"""Enemy chase AI pattern"""
|
||||
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
|
||||
|
||||
player = mcrfpy.Entity(grid_pos=(15, 15), sprite_index=0, name="player")
|
||||
enemy = mcrfpy.Entity(grid_pos=(5, 5), sprite_index=1, name="enemy")
|
||||
grid.entities.append(player)
|
||||
grid.entities.append(enemy)
|
||||
|
||||
# Chase: use dijkstra from player, step enemy toward player
|
||||
dm = grid.get_dijkstra_map((int(player.grid_x), int(player.grid_y)))
|
||||
next_step = dm.step_from((int(enemy.grid_x), int(enemy.grid_y)))
|
||||
assert next_step is not None
|
||||
# Move enemy
|
||||
enemy.grid_x = int(next_step.x)
|
||||
enemy.grid_y = int(next_step.y)
|
||||
|
||||
check("AIP: chase pattern", test_aip_chase_pattern)
|
||||
|
||||
def test_aip_wasd_fov():
|
||||
"""WASD + FOV update pattern"""
|
||||
scene = mcrfpy.Scene("aip_wasd")
|
||||
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
|
||||
grid.at(x, y).transparent = True
|
||||
scene.children.append(grid)
|
||||
|
||||
player = mcrfpy.Entity(grid_pos=(10, 10), sprite_index=0)
|
||||
grid.entities.append(player)
|
||||
grid.perspective = player
|
||||
|
||||
def on_player_move(dx, dy):
|
||||
new_x = int(player.grid_x + dx)
|
||||
new_y = int(player.grid_y + dy)
|
||||
point = grid.at(new_x, new_y)
|
||||
if point and point.walkable:
|
||||
player.grid_x = new_x
|
||||
player.grid_y = new_y
|
||||
grid.compute_fov((new_x, new_y), radius=10)
|
||||
|
||||
on_player_move(1, 0)
|
||||
assert player.grid_x == 11
|
||||
|
||||
move_map = {
|
||||
mcrfpy.Key.W: (0, -1),
|
||||
mcrfpy.Key.A: (-1, 0),
|
||||
mcrfpy.Key.S: (0, 1),
|
||||
mcrfpy.Key.D: (1, 0),
|
||||
}
|
||||
|
||||
def handle_key(key, action):
|
||||
if action != mcrfpy.InputState.PRESSED:
|
||||
return
|
||||
if key in move_map:
|
||||
dx, dy = move_map[key]
|
||||
on_player_move(dx, dy)
|
||||
|
||||
scene.on_key = handle_key
|
||||
|
||||
check("AIP: WASD + FOV pattern", test_aip_wasd_fov)
|
||||
|
||||
def test_aip_spatial_query():
|
||||
"""Spatial query for AI aggro"""
|
||||
grid = mcrfpy.Grid(grid_size=(50, 50), pos=(0, 0), size=(400, 400))
|
||||
for x in range(50):
|
||||
for y in range(50):
|
||||
grid.at(x, y).walkable = True
|
||||
|
||||
player = mcrfpy.Entity(grid_pos=(10, 10), sprite_index=0, name="p")
|
||||
enemy = mcrfpy.Entity(grid_pos=(12, 10), sprite_index=1, name="e")
|
||||
grid.entities.append(player)
|
||||
grid.entities.append(enemy)
|
||||
|
||||
# Check aggro range
|
||||
nearby = grid.entities_in_radius((int(enemy.grid_x), int(enemy.grid_y)), 5.0)
|
||||
assert len(nearby) >= 2 # enemy and player both in range
|
||||
|
||||
check("AIP: spatial query for aggro", test_aip_spatial_query)
|
||||
|
||||
# ===================================================================
|
||||
print("\n=== WRITING TESTS ===")
|
||||
# ===================================================================
|
||||
|
||||
def test_wt_direct_execution():
|
||||
"""Direct execution test template"""
|
||||
scene = mcrfpy.Scene("wt_test")
|
||||
frame = mcrfpy.Frame(pos=(100, 100), size=(200, 150))
|
||||
frame.fill_color = mcrfpy.Color(255, 0, 0)
|
||||
scene.children.append(frame)
|
||||
assert frame.x == 100
|
||||
assert frame.w == 200
|
||||
|
||||
check("WT: direct execution template", test_wt_direct_execution)
|
||||
|
||||
def test_wt_property_roundtrip():
|
||||
"""Property round-trip test pattern"""
|
||||
obj = mcrfpy.Frame(pos=(0, 0), size=(100, 100))
|
||||
test_values = [0, 50, 100, 255, 127]
|
||||
for value in test_values:
|
||||
obj.x = value
|
||||
assert obj.x == value, f"Failed for {value}"
|
||||
|
||||
check("WT: property round-trip", test_wt_property_roundtrip)
|
||||
|
||||
def test_wt_exception_testing():
|
||||
"""Exception testing pattern"""
|
||||
grid = mcrfpy.Grid(grid_size=(10, 10), pos=(0, 0), size=(160, 160))
|
||||
try:
|
||||
grid.at(-1, -1)
|
||||
assert False, "Should have raised"
|
||||
except Exception:
|
||||
pass # Expected
|
||||
|
||||
check("WT: exception testing", test_wt_exception_testing)
|
||||
|
||||
def test_wt_grid_test_pattern():
|
||||
"""Grid test pattern"""
|
||||
grid = mcrfpy.Grid(grid_size=(10, 10), pos=(0, 0), size=(160, 160))
|
||||
grid.at(5, 5).walkable = True
|
||||
assert grid.at(5, 5).walkable == True
|
||||
|
||||
check("WT: grid test pattern", test_wt_grid_test_pattern)
|
||||
|
||||
def test_wt_click_callback_setup():
|
||||
"""Click callback test setup"""
|
||||
clicks_received = []
|
||||
scene = mcrfpy.Scene("wt_click")
|
||||
frame = mcrfpy.Frame(pos=(100, 100), size=(200, 150),
|
||||
fill_color=mcrfpy.Color(0, 255, 0))
|
||||
def on_click(pos, button, action):
|
||||
clicks_received.append((pos, button, action))
|
||||
frame.on_click = on_click
|
||||
scene.children.append(frame)
|
||||
|
||||
check("WT: click callback setup", test_wt_click_callback_setup)
|
||||
|
||||
def test_wt_timer_pattern():
|
||||
"""Timer creation pattern"""
|
||||
t = mcrfpy.Timer("wt_test_timer", lambda timer, runtime: None, 100)
|
||||
assert t is not None
|
||||
t.stop()
|
||||
|
||||
check("WT: timer creation", test_wt_timer_pattern)
|
||||
|
||||
# ===================================================================
|
||||
print("\n=== HEADLESS MODE ===")
|
||||
# ===================================================================
|
||||
|
||||
def test_hm_step():
|
||||
"""Step function"""
|
||||
dt = mcrfpy.step(0.1)
|
||||
# In headless mode, returns the dt
|
||||
assert dt is not None
|
||||
|
||||
check("HM: step()", test_hm_step)
|
||||
|
||||
def test_hm_timer_with_step():
|
||||
"""Timer fires with step"""
|
||||
fired = [False]
|
||||
def on_timer(timer, runtime):
|
||||
fired[0] = True
|
||||
t = mcrfpy.Timer("hm_test", on_timer, 500)
|
||||
mcrfpy.step(0.6) # 600ms - timer should fire
|
||||
assert fired[0], "Timer should have fired"
|
||||
t.stop()
|
||||
|
||||
check("HM: timer with step", test_hm_timer_with_step)
|
||||
|
||||
def test_hm_animation_with_step():
|
||||
"""Animation updates with step"""
|
||||
frame = mcrfpy.Frame(pos=(0, 0), size=(100, 100))
|
||||
frame.animate("x", 500.0, 2.0, mcrfpy.Easing.EASE_IN_OUT)
|
||||
mcrfpy.step(1.0)
|
||||
# Should be roughly halfway
|
||||
assert frame.x > 0 # At least started moving
|
||||
|
||||
check("HM: animation with step", test_hm_animation_with_step)
|
||||
|
||||
def test_hm_scene_setup():
|
||||
"""Scene setup in headless"""
|
||||
scene = mcrfpy.Scene("hm_test")
|
||||
frame = mcrfpy.Frame(pos=(50, 50), size=(100, 100))
|
||||
scene.children.append(frame)
|
||||
mcrfpy.current_scene = scene
|
||||
assert frame.x == 50
|
||||
|
||||
check("HM: scene setup headless", test_hm_scene_setup)
|
||||
|
||||
# ===================================================================
|
||||
print("\n=== UI COMPONENT HIERARCHY ===")
|
||||
# ===================================================================
|
||||
|
||||
def test_uch_parent_child():
|
||||
"""Parent-child coordinates"""
|
||||
frame = mcrfpy.Frame(pos=(100, 100), size=(200, 150))
|
||||
label = mcrfpy.Caption(text="Hello", pos=(10, 10))
|
||||
frame.children.append(label)
|
||||
assert label.x == 10 # Relative to parent
|
||||
|
||||
check("UCH: parent-child coords", test_uch_parent_child)
|
||||
|
||||
def test_uch_all_types():
|
||||
"""All drawable types exist"""
|
||||
f = mcrfpy.Frame(pos=(0, 0), size=(100, 100))
|
||||
c = mcrfpy.Caption(text="test", pos=(0, 0))
|
||||
s = mcrfpy.Sprite(x=0, y=0, sprite_index=0)
|
||||
g = mcrfpy.Grid(grid_size=(10, 10), pos=(0, 0), size=(160, 160))
|
||||
e = mcrfpy.Entity(grid_pos=(0, 0), sprite_index=0)
|
||||
assert hasattr(mcrfpy, 'Arc')
|
||||
assert hasattr(mcrfpy, 'Circle')
|
||||
assert hasattr(mcrfpy, 'Line')
|
||||
|
||||
check("UCH: all drawable types", test_uch_all_types)
|
||||
|
||||
def test_uch_common_properties():
|
||||
"""Common UIDrawable properties"""
|
||||
f = mcrfpy.Frame(pos=(50, 60), size=(100, 100))
|
||||
assert f.x == 50
|
||||
assert f.y == 60
|
||||
assert f.w == 100
|
||||
assert f.h == 100
|
||||
f.visible = False
|
||||
assert f.visible == False
|
||||
f.visible = True
|
||||
f.opacity = 0.5
|
||||
assert f.opacity == 0.5
|
||||
f.z_index = 42
|
||||
assert f.z_index == 42
|
||||
|
||||
check("UCH: common properties", test_uch_common_properties)
|
||||
|
||||
def test_uch_click_callbacks():
|
||||
"""Callback signatures"""
|
||||
f = mcrfpy.Frame(pos=(0, 0), size=(100, 100))
|
||||
# on_click: (pos: Vector, button: MouseButton, action: InputState)
|
||||
f.on_click = lambda pos, button, action: None
|
||||
# on_enter/on_exit: (pos: Vector)
|
||||
f.on_enter = lambda pos: None
|
||||
f.on_exit = lambda pos: None
|
||||
# on_move: (pos: Vector)
|
||||
f.on_move = lambda pos: None
|
||||
|
||||
check("UCH: callback signatures", test_uch_click_callbacks)
|
||||
|
||||
def test_uch_collection():
|
||||
"""UICollection operations"""
|
||||
scene = mcrfpy.Scene("uch_coll")
|
||||
f1 = mcrfpy.Frame(pos=(0, 0), size=(10, 10))
|
||||
f2 = mcrfpy.Caption(text="test", pos=(0, 0))
|
||||
f3 = mcrfpy.Sprite(x=0, y=0, sprite_index=0)
|
||||
scene.children.append(f1)
|
||||
scene.children.append(f2)
|
||||
scene.children.append(f3)
|
||||
assert len(scene.children) >= 3
|
||||
# Can iterate
|
||||
for item in scene.children:
|
||||
pass
|
||||
|
||||
check("UCH: UICollection", test_uch_collection)
|
||||
|
||||
def test_uch_entity_collection():
|
||||
"""UIEntityCollection operations"""
|
||||
grid = mcrfpy.Grid(grid_size=(20, 20), pos=(0, 0), size=(320, 320))
|
||||
e1 = mcrfpy.Entity(grid_pos=(1, 1), sprite_index=0)
|
||||
e2 = mcrfpy.Entity(grid_pos=(2, 2), sprite_index=0)
|
||||
grid.entities.append(e1)
|
||||
grid.entities.append(e2)
|
||||
assert len(grid.entities) == 2
|
||||
grid.entities.remove(e1)
|
||||
assert len(grid.entities) == 1
|
||||
|
||||
check("UCH: EntityCollection", test_uch_entity_collection)
|
||||
|
||||
def test_uch_type_preservation():
|
||||
"""Type preserved through collections"""
|
||||
scene = mcrfpy.Scene("uch_types")
|
||||
sprite = mcrfpy.Sprite(x=10, y=10, sprite_index=0)
|
||||
scene.children.append(sprite)
|
||||
retrieved = scene.children[0]
|
||||
assert type(retrieved).__name__ == "Sprite"
|
||||
|
||||
check("UCH: type preservation", test_uch_type_preservation)
|
||||
|
||||
# ===================================================================
|
||||
print("\n" + "=" * 60)
|
||||
print(f"PHASE D2 VERIFICATION: {passes} passed, {fails} failed")
|
||||
print("=" * 60)
|
||||
|
||||
if fails:
|
||||
sys.exit(1)
|
||||
else:
|
||||
sys.exit(0)
|
||||
Loading…
Add table
Add a link
Reference in a new issue