diff --git a/tests/conftest.py b/tests/conftest.py index aeac22c..981e78f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -111,7 +111,7 @@ def pytest_collect_file(parent, file_path): except ValueError: return None - if rel_path.parts and rel_path.parts[0] in ('unit', 'integration', 'regression'): + if rel_path.parts and rel_path.parts[0] in ('unit', 'integration', 'regression', 'docs', 'demo'): if file_path.suffix == '.py' and file_path.name not in ('__init__.py', 'conftest.py'): return McRFTestFile.from_parent(parent, path=file_path) return None @@ -121,7 +121,7 @@ def pytest_ignore_collect(collection_path, config): """Prevent pytest from trying to import test scripts as Python modules.""" try: rel_path = collection_path.relative_to(TESTS_DIR) - if rel_path.parts and rel_path.parts[0] in ('unit', 'integration', 'regression'): + if rel_path.parts and rel_path.parts[0] in ('unit', 'integration', 'regression', 'docs', 'demo'): # Let our custom collector handle these, don't import them return False # Don't ignore - we'll collect them our way except ValueError: diff --git a/tests/docs/API_FINDINGS.md b/tests/docs/API_FINDINGS.md new file mode 100644 index 0000000..b4cce5f --- /dev/null +++ b/tests/docs/API_FINDINGS.md @@ -0,0 +1,129 @@ +# McRogueFace API Test Findings +*Generated by Frack, January 14, 2026* + +## Summary + +Tested code snippets from docs site against actual runtime API. +Tests created in `/tests/docs/` with screenshots in `/tests/docs/screenshots/`. + +--- + +## Entity Constructor + +**Correct:** +```python +entity = mcrfpy.Entity(grid_pos=(10, 7), texture=texture, sprite_index=84) +``` + +**Wrong:** +```python +entity = mcrfpy.Entity(pos=(10, 7), ...) # FAILS - no 'pos' kwarg +entity = mcrfpy.Entity(grid_x=10, grid_y=7, ...) # FAILS - no separate kwargs +``` + +--- + +## Scene API + +**Modern (WORKS):** +```python +scene = mcrfpy.Scene("name") +scene.children.append(frame) +scene.on_key = handler +scene.activate() +``` + +**Deprecated → Modern:** +```python +# OLD → NEW +mcrfpy.createScene("name") → scene = mcrfpy.Scene("name") +mcrfpy.sceneUI("name") → scene.children +mcrfpy.setScene("name") → scene.activate() +mcrfpy.keypressScene(fn) → scene.on_key = fn +mcrfpy.currentScene() → mcrfpy.current_scene # property, not function! +``` + +--- + +## Grid.at() Signature + +Both work: +```python +point = grid.at((x, y)) # Tuple - documented +point = grid.at(x, y) # Separate args - also works! +``` + +--- + +## Animation System + +**Works:** +- `x`, `y`, `w`, `h` properties animate correctly +- Callbacks fire as expected +- Multiple simultaneous animations work +- Easing functions work + +**Does NOT work:** +- `opacity` - property exists, can set directly, but animation ignores it + +--- + +## Timer API + +**Modern:** +```python +timer = mcrfpy.Timer("name", callback, seconds) +# Callback signature: def callback(timer, runtime): +``` + +**Deprecated:** +```python +mcrfpy.setTimer("name", callback, milliseconds) # Wrong signature too +``` + +--- + +## Color API + +Always use `mcrfpy.Color()`: +```python +frame.fill_color = mcrfpy.Color(255, 0, 0) # CORRECT +frame.fill_color = mcrfpy.Color(255, 0, 0, 128) # With alpha +``` + +Tuples no longer work: +```python +frame.fill_color = (255, 0, 0) # FAILS +``` + +--- + +## Available Globals + +**All exist:** +- `mcrfpy.default_texture` - Texture for kenney_tinydungeon.png +- `mcrfpy.default_font` - Font for JetBrains Mono +- `mcrfpy.default_fov` - (default FOV settings) + +--- + +## Files Requiring Updates + +1. `quickstart.md` - All 4 code blocks use deprecated API +2. `features/scenes.md` - "Procedural API" section entirely deprecated +3. `features/animation.md` - opacity examples don't work +4. Any file using `setTimer`, `createScene`, `sceneUI`, `setScene`, `keypressScene` + +--- + +## Test Files Created + +| Test | Status | Notes | +|------|--------|-------| +| test_quickstart_simple_scene.py | PASS | | +| test_quickstart_main_menu.py | PASS | | +| test_quickstart_entities.py | PASS | Uses grid_pos= | +| test_quickstart_sprites.py | PASS | | +| test_features_animation.py | PASS | opacity test skipped | +| test_features_scenes.py | PASS | Documents deprecated API | +| test_entity_api.py | INFO | Verifies grid_pos= works | diff --git a/tests/docs/screenshots/features_animation.png b/tests/docs/screenshots/features_animation.png new file mode 100644 index 0000000..4280a2c Binary files /dev/null and b/tests/docs/screenshots/features_animation.png differ diff --git a/tests/docs/screenshots/features_scenes.png b/tests/docs/screenshots/features_scenes.png new file mode 100644 index 0000000..1c8ee92 Binary files /dev/null and b/tests/docs/screenshots/features_scenes.png differ diff --git a/tests/docs/screenshots/quickstart_entities.png b/tests/docs/screenshots/quickstart_entities.png new file mode 100644 index 0000000..da85c34 Binary files /dev/null and b/tests/docs/screenshots/quickstart_entities.png differ diff --git a/tests/docs/screenshots/quickstart_main_menu.png b/tests/docs/screenshots/quickstart_main_menu.png new file mode 100644 index 0000000..6bb58d6 Binary files /dev/null and b/tests/docs/screenshots/quickstart_main_menu.png differ diff --git a/tests/docs/screenshots/quickstart_simple_scene.png b/tests/docs/screenshots/quickstart_simple_scene.png new file mode 100644 index 0000000..e90b37d Binary files /dev/null and b/tests/docs/screenshots/quickstart_simple_scene.png differ diff --git a/tests/docs/screenshots/quickstart_sprites.png b/tests/docs/screenshots/quickstart_sprites.png new file mode 100644 index 0000000..a5d420e Binary files /dev/null and b/tests/docs/screenshots/quickstart_sprites.png differ diff --git a/tests/docs/test_current_scene.py b/tests/docs/test_current_scene.py new file mode 100644 index 0000000..80eb18f --- /dev/null +++ b/tests/docs/test_current_scene.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +"""Verify mcrfpy.current_scene property.""" +import mcrfpy +import sys + +scene = mcrfpy.Scene("test") +scene.activate() +mcrfpy.step(0.1) + +try: + current = mcrfpy.current_scene + print(f"mcrfpy.current_scene = {current}") + print(f"type: {type(current)}") + print("VERIFIED: mcrfpy.current_scene WORKS") +except AttributeError as e: + print(f"FAILED: {e}") + +sys.exit(0) diff --git a/tests/docs/test_defaults.py b/tests/docs/test_defaults.py new file mode 100644 index 0000000..6105cfc --- /dev/null +++ b/tests/docs/test_defaults.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +"""Test mcrfpy default resources.""" +import mcrfpy +import sys + +scene = mcrfpy.Scene("test") +scene.activate() +mcrfpy.step(0.01) + +print("Checking mcrfpy defaults:") + +try: + dt = mcrfpy.default_texture + print(f" default_texture = {dt}") +except AttributeError as e: + print(f" default_texture: NOT FOUND") + +try: + df = mcrfpy.default_font + print(f" default_font = {df}") +except AttributeError as e: + print(f" default_font: NOT FOUND") + +# Also check what other module-level attributes exist +print("\nAll mcrfpy attributes starting with 'default':") +for attr in dir(mcrfpy): + if 'default' in attr.lower(): + print(f" {attr}") + +sys.exit(0) diff --git a/tests/docs/test_entity_api.py b/tests/docs/test_entity_api.py new file mode 100644 index 0000000..6cc8601 --- /dev/null +++ b/tests/docs/test_entity_api.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +"""Quick test to verify Entity constructor signature.""" +import mcrfpy +import sys + +scene = mcrfpy.Scene("test") +scene.activate() +mcrfpy.step(0.01) + +texture = mcrfpy.Texture("assets/kenney_tinydungeon.png", 16, 16) +grid = mcrfpy.Grid(grid_size=(20, 15), texture=texture, pos=(10, 10), size=(640, 480)) +scene.children.append(grid) + +# Test grid_pos vs grid_x/grid_y +try: + e1 = mcrfpy.Entity(grid_pos=(5, 5), texture=texture, sprite_index=85) + grid.entities.append(e1) + print("grid_pos= WORKS") +except TypeError as e: + print(f"grid_pos= FAILS: {e}") + +try: + e2 = mcrfpy.Entity(grid_x=7, grid_y=7, texture=texture, sprite_index=85) + grid.entities.append(e2) + print("grid_x=/grid_y= WORKS") +except TypeError as e: + print(f"grid_x=/grid_y= FAILS: {e}") + +print("Entity API test complete") +sys.exit(0) diff --git a/tests/docs/test_features_animation.py b/tests/docs/test_features_animation.py new file mode 100644 index 0000000..2a40238 --- /dev/null +++ b/tests/docs/test_features_animation.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +"""Test for features/animation.md examples. + +Tests the modern API equivalents of animation examples. +""" +import mcrfpy +from mcrfpy import automation +import sys + +# Setup scene using modern API +scene = mcrfpy.Scene("animation_demo") +scene.activate() +mcrfpy.step(0.01) + +# Test 1: Basic Animation (lines 9-19) +frame = mcrfpy.Frame(pos=(0, 0), size=(100, 100)) +frame.fill_color = mcrfpy.Color(255, 0, 0) +scene.children.append(frame) + +# Animate x position +anim = mcrfpy.Animation("x", 500.0, 2.0, "easeInOut") +anim.start(frame) +print("Test 1: Basic animation started") + +# Step forward to run animation +mcrfpy.step(2.5) + +# Verify animation completed +if abs(frame.x - 500.0) < 1.0: + print("Test 1: PASS - frame moved to x=500") +else: + print(f"Test 1: FAIL - frame at x={frame.x}, expected 500") + sys.exit(1) + +# Test 2: Multiple simultaneous animations (lines 134-144) +frame2 = mcrfpy.Frame(pos=(0, 0), size=(100, 100)) +frame2.fill_color = mcrfpy.Color(0, 255, 0) +scene.children.append(frame2) + +mcrfpy.Animation("x", 200.0, 1.0, "easeInOut").start(frame2) +mcrfpy.Animation("y", 150.0, 1.0, "easeInOut").start(frame2) +mcrfpy.Animation("w", 300.0, 1.0, "easeInOut").start(frame2) +mcrfpy.Animation("h", 200.0, 1.0, "easeInOut").start(frame2) + +mcrfpy.step(1.5) + +if abs(frame2.x - 200.0) < 1.0 and abs(frame2.y - 150.0) < 1.0: + print("Test 2: PASS - multiple animations completed") +else: + print(f"Test 2: FAIL - frame2 at ({frame2.x}, {frame2.y})") + sys.exit(1) + +# Test 3: Callback (lines 105-112) +callback_fired = False + +def on_complete(animation, target): + global callback_fired + callback_fired = True + print("Test 3: Callback fired!") + +frame3 = mcrfpy.Frame(pos=(0, 300), size=(50, 50)) +frame3.fill_color = mcrfpy.Color(0, 0, 255) +scene.children.append(frame3) + +anim3 = mcrfpy.Animation("x", 300.0, 0.5, "easeInOut", callback=on_complete) +anim3.start(frame3) + +mcrfpy.step(1.0) + +if callback_fired: + print("Test 3: PASS - callback executed") +else: + print("Test 3: FAIL - callback not executed") + sys.exit(1) + +# Test 4: NOTE - Opacity animation documented in features/animation.md +# but DOES NOT WORK on Frame. The property exists but animation +# system doesn't animate it. This is a DOCS BUG to report. +# Skipping test 4 - opacity animation not supported. +print("Test 4: SKIPPED - opacity animation not supported on Frame (docs bug)") + +# Take screenshot showing animation results +automation.screenshot("/opt/goblincorps/repos/McRogueFace/tests/docs/screenshots/features_animation.png") + +print("\nAll animation tests PASS") +sys.exit(0) diff --git a/tests/docs/test_features_scenes.py b/tests/docs/test_features_scenes.py new file mode 100644 index 0000000..89f6a6d --- /dev/null +++ b/tests/docs/test_features_scenes.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +"""Test for features/scenes.md examples. + +Tests both modern and procedural APIs from the docs. +""" +import mcrfpy +from mcrfpy import automation +import sys + +# Test 1: Modern Scene API (lines 28-42) +print("Test 1: Modern Scene API") +scene = mcrfpy.Scene("test_modern") +scene.children.append(mcrfpy.Frame(pos=(0, 0), size=(800, 600))) + +def my_handler(key, action): + if action == "start": + print(f" Key handler received: {key}") + +scene.on_key = my_handler +scene.activate() +mcrfpy.step(0.1) +print(" PASS - modern Scene API works") + +# Test 2: Check Scene properties +print("Test 2: Scene properties") +print(f" scene.name = {scene.name}") +print(f" scene.active = {scene.active}") +print(f" len(scene.children) = {len(scene.children)}") + +# Test 3: Check if default_texture exists +print("Test 3: default_texture") +try: + dt = mcrfpy.default_texture + print(f" mcrfpy.default_texture = {dt}") +except AttributeError: + print(" default_texture NOT FOUND - docs bug!") + +# Test 4: Check if currentScene exists +print("Test 4: currentScene()") +try: + current = mcrfpy.currentScene() + print(f" mcrfpy.currentScene() = {current}") +except AttributeError: + print(" currentScene() NOT FOUND - docs bug!") + +# Test 5: Check Grid.at() signature +print("Test 5: Grid.at() signature") +texture = mcrfpy.Texture("assets/kenney_tinydungeon.png", 16, 16) +grid = mcrfpy.Grid(grid_size=(10, 10), texture=texture, pos=(0, 0), size=(200, 200)) + +# Try both signatures +try: + point_tuple = grid.at((5, 5)) + print(" grid.at((x, y)) - tuple WORKS") +except Exception as e: + print(f" grid.at((x, y)) FAILS: {e}") + +try: + point_sep = grid.at(5, 5) + print(" grid.at(x, y) - separate args WORKS") +except Exception as e: + print(f" grid.at(x, y) FAILS: {e}") + +# Test 6: Scene transitions (setScene) +print("Test 6: setScene()") +scene2 = mcrfpy.Scene("test_transitions") +scene2.activate() +mcrfpy.step(0.1) + +# Check if setScene exists +try: + mcrfpy.setScene("test_modern") + print(" mcrfpy.setScene() WORKS") +except AttributeError: + print(" mcrfpy.setScene() NOT FOUND - use scene.activate() instead") +except Exception as e: + print(f" mcrfpy.setScene() error: {e}") + +# Take screenshot +mcrfpy.step(0.1) +automation.screenshot("/opt/goblincorps/repos/McRogueFace/tests/docs/screenshots/features_scenes.png") + +print("\nAll scene tests complete") +sys.exit(0) diff --git a/tests/docs/test_quickstart_entities.py b/tests/docs/test_quickstart_entities.py new file mode 100644 index 0000000..dfc668f --- /dev/null +++ b/tests/docs/test_quickstart_entities.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +"""Test for quickstart.md 'Game Entity' example. + +Original (DEPRECATED - lines 133-168): + mcrfpy.createScene("game") + grid = mcrfpy.Grid(20, 15, texture, (10, 10), (640, 480)) + ui = mcrfpy.sceneUI("game") + player = mcrfpy.Entity((10, 7), texture, 85) + mcrfpy.keypressScene(handle_keys) + mcrfpy.setScene("game") + +Modern equivalent below. +""" +import mcrfpy +from mcrfpy import automation +import sys + +# Create scene using modern API +scene = mcrfpy.Scene("game") +scene.activate() +mcrfpy.step(0.01) + +# Load texture +texture = mcrfpy.Texture("assets/kenney_tinydungeon.png", 16, 16) + +# Create grid using modern keyword API +grid = mcrfpy.Grid( + grid_size=(20, 15), + texture=texture, + pos=(10, 10), + size=(640, 480) +) +scene.children.append(grid) + +# Add player entity +player = mcrfpy.Entity(grid_pos=(10, 7), texture=texture, sprite_index=85) +grid.entities.append(player) + +# Add NPC entity +npc = mcrfpy.Entity(grid_pos=(5, 5), texture=texture, sprite_index=109) +grid.entities.append(npc) + +# Add treasure chest +treasure = mcrfpy.Entity(grid_pos=(15, 10), texture=texture, sprite_index=89) +grid.entities.append(treasure) + +# Movement handler using modern API +def handle_keys(key, state): + if state == "start": + x, y = player.pos[0], player.pos[1] + if key == "W": + player.pos = (x, y - 1) + elif key == "S": + player.pos = (x, y + 1) + elif key == "A": + player.pos = (x - 1, y) + elif key == "D": + player.pos = (x + 1, y) + +scene.on_key = handle_keys + +# Center grid on player +grid.center = (10, 7) + +# Render and screenshot +mcrfpy.step(0.1) +automation.screenshot("/opt/goblincorps/repos/McRogueFace/tests/docs/screenshots/quickstart_entities.png") + +print("PASS - quickstart entities") +sys.exit(0) diff --git a/tests/docs/test_quickstart_main_menu.py b/tests/docs/test_quickstart_main_menu.py new file mode 100644 index 0000000..30a9a0d --- /dev/null +++ b/tests/docs/test_quickstart_main_menu.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +"""Test for quickstart.md 'Main Menu' example. + +Original (DEPRECATED - lines 82-125): + mcrfpy.createScene("main_menu") + ui = mcrfpy.sceneUI("main_menu") + bg = mcrfpy.Frame(0, 0, 1024, 768, fill_color=(20, 20, 40)) + title = mcrfpy.Caption((312, 100), "My Awesome Game", font, fill_color=(255, 255, 100)) + button_frame.click = start_game + mcrfpy.setScene("main_menu") + +Modern equivalent below. +""" +import mcrfpy +from mcrfpy import automation +import sys + +# Create scene using modern API +scene = mcrfpy.Scene("main_menu") +scene.activate() +mcrfpy.step(0.01) + +# Load font +font = mcrfpy.Font("assets/JetbrainsMono.ttf") + +# Add background using modern Frame API (keyword args) +bg = mcrfpy.Frame( + pos=(0, 0), + size=(1024, 768), + fill_color=mcrfpy.Color(20, 20, 40) +) +scene.children.append(bg) + +# Add title using modern Caption API +title = mcrfpy.Caption( + pos=(312, 100), + text="My Awesome Game", + font=font, + fill_color=mcrfpy.Color(255, 255, 100) +) +title.font_size = 48 +title.outline = 2 +title.outline_color = mcrfpy.Color(0, 0, 0) +scene.children.append(title) + +# Create button frame +button_frame = mcrfpy.Frame( + pos=(362, 300), + size=(300, 80), + fill_color=mcrfpy.Color(50, 150, 50) +) + +# Button caption +button_caption = mcrfpy.Caption( + pos=(90, 25), # Centered in button + text="Start Game", + fill_color=mcrfpy.Color(255, 255, 255) +) +button_caption.font_size = 24 +button_frame.children.append(button_caption) + +# Click handler using modern on_click (3 args: x, y, button) +def start_game(x, y, button): + print("Starting the game!") + +button_frame.on_click = start_game +scene.children.append(button_frame) + +# Render and screenshot +mcrfpy.step(0.1) +automation.screenshot("/opt/goblincorps/repos/McRogueFace/tests/docs/screenshots/quickstart_main_menu.png") + +print("PASS - quickstart main menu") +sys.exit(0) diff --git a/tests/docs/test_quickstart_simple_scene.py b/tests/docs/test_quickstart_simple_scene.py new file mode 100644 index 0000000..fdcb4f3 --- /dev/null +++ b/tests/docs/test_quickstart_simple_scene.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +"""Test for quickstart.md 'Simple Test Scene' example. + +Original (DEPRECATED - lines 48-74): + mcrfpy.createScene("test") + grid = mcrfpy.Grid(20, 15, texture, (10, 10), (800, 600)) + ui = mcrfpy.sceneUI("test") + mcrfpy.setScene("test") + mcrfpy.keypressScene(move_around) + +Modern equivalent below. +""" +import mcrfpy +from mcrfpy import automation +import sys + +# Create scene using modern API +scene = mcrfpy.Scene("test") +scene.activate() +mcrfpy.step(0.01) # Initialize + +# Load texture +texture = mcrfpy.Texture("assets/kenney_tinydungeon.png", 16, 16) + +# Create grid using modern keyword API +grid = mcrfpy.Grid( + grid_size=(20, 15), + texture=texture, + pos=(10, 10), + size=(800, 600) +) + +# Add to scene's children (not sceneUI) +scene.children.append(grid) + +# Add keyboard controls using modern API +def move_around(key, state): + if state == "start": + print(f"You pressed {key}") + +scene.on_key = move_around + +# Render and screenshot +mcrfpy.step(0.1) +automation.screenshot("/opt/goblincorps/repos/McRogueFace/tests/docs/screenshots/quickstart_simple_scene.png") + +print("PASS - quickstart simple scene") +sys.exit(0) diff --git a/tests/docs/test_quickstart_sprites.py b/tests/docs/test_quickstart_sprites.py new file mode 100644 index 0000000..2975a48 --- /dev/null +++ b/tests/docs/test_quickstart_sprites.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +"""Test for quickstart.md 'Custom Sprite Sheet' example. + +Original (DEPRECATED - lines 176-201): + mcrfpy.createScene("game") + grid = mcrfpy.Grid(20, 15, my_texture, (10, 10), (640, 480)) + grid.at(5, 5).sprite = 10 + ui = mcrfpy.sceneUI("game") + mcrfpy.setScene("game") + +Modern equivalent below. +""" +import mcrfpy +from mcrfpy import automation +import sys + +# Create scene using modern API +scene = mcrfpy.Scene("game") +scene.activate() +mcrfpy.step(0.01) + +# Load sprite sheet (using existing texture for test) +texture = mcrfpy.Texture("assets/kenney_tinydungeon.png", 16, 16) + +# Create grid using modern keyword API +grid = mcrfpy.Grid( + grid_size=(20, 15), + texture=texture, + pos=(10, 10), + size=(640, 480) +) + +# Set specific tiles using modern API +# grid.at() returns a GridPoint with tilesprite property +grid.at((5, 5)).tilesprite = 10 # Note: tuple for position +grid.at((6, 5)).tilesprite = 11 + +# Set walkability +grid.at((6, 5)).walkable = False + +# Add grid to scene +scene.children.append(grid) + +# Render and screenshot +mcrfpy.step(0.1) +automation.screenshot("/opt/goblincorps/repos/McRogueFace/tests/docs/screenshots/quickstart_sprites.png") + +print("PASS - quickstart sprites") +sys.exit(0)