#!/usr/bin/env python3 """ McRogueFace Exhaustive API Demonstration ======================================== This script demonstrates EVERY constructor variant and EVERY method for EVERY UI object type in McRogueFace. It serves as both a test suite and a comprehensive API reference with working examples. The script is organized by UI object type, showing: 1. All constructor variants (empty, partial args, full args) 2. All properties (get and set) 3. All methods with different parameter combinations 4. Special behaviors and edge cases Author: Claude Purpose: Complete API demonstration and validation """ import mcrfpy from mcrfpy import Color, Vector, Font, Texture, Frame, Caption, Sprite, Grid, Entity import sys # Test configuration VERBOSE = True # Print detailed information about each test def print_section(title): """Print a section header""" print("\n" + "="*60) print(f" {title}") print("="*60) def print_test(test_name, success=True): """Print test result""" status = "✓ PASS" if success else "✗ FAIL" print(f" {status} - {test_name}") def test_color_api(): """Test all Color constructors and methods""" print_section("COLOR API TESTS") # Constructor variants print("\n Constructors:") # Empty constructor (defaults to white) c1 = Color() print_test(f"Color() = ({c1.r}, {c1.g}, {c1.b}, {c1.a})") # Single value (grayscale) c2 = Color(128) print_test(f"Color(128) = ({c2.r}, {c2.g}, {c2.b}, {c2.a})") # RGB only (alpha defaults to 255) c3 = Color(255, 128, 0) print_test(f"Color(255, 128, 0) = ({c3.r}, {c3.g}, {c3.b}, {c3.a})") # Full RGBA c4 = Color(100, 150, 200, 128) print_test(f"Color(100, 150, 200, 128) = ({c4.r}, {c4.g}, {c4.b}, {c4.a})") # From hex string c5 = Color.from_hex("#FF8800") print_test(f"Color.from_hex('#FF8800') = ({c5.r}, {c5.g}, {c5.b}, {c5.a})") c6 = Color.from_hex("#FF8800AA") print_test(f"Color.from_hex('#FF8800AA') = ({c6.r}, {c6.g}, {c6.b}, {c6.a})") # Methods print("\n Methods:") # to_hex hex_str = c4.to_hex() print_test(f"Color(100, 150, 200, 128).to_hex() = '{hex_str}'") # lerp (linear interpolation) c_start = Color(0, 0, 0) c_end = Color(255, 255, 255) c_mid = c_start.lerp(c_end, 0.5) print_test(f"Black.lerp(White, 0.5) = ({c_mid.r}, {c_mid.g}, {c_mid.b}, {c_mid.a})") # Property access print("\n Properties:") c = Color(10, 20, 30, 40) print_test(f"Initial: r={c.r}, g={c.g}, b={c.b}, a={c.a}") c.r = 200 c.g = 150 c.b = 100 c.a = 255 print_test(f"After modification: r={c.r}, g={c.g}, b={c.b}, a={c.a}") return True def test_vector_api(): """Test all Vector constructors and methods""" print_section("VECTOR API TESTS") # Constructor variants print("\n Constructors:") # Empty constructor v1 = Vector() print_test(f"Vector() = ({v1.x}, {v1.y})") # Single value (both x and y) v2 = Vector(5.0) print_test(f"Vector(5.0) = ({v2.x}, {v2.y})") # Full x, y v3 = Vector(10.5, 20.3) print_test(f"Vector(10.5, 20.3) = ({v3.x}, {v3.y})") # Methods print("\n Methods:") # magnitude v = Vector(3, 4) mag = v.magnitude() print_test(f"Vector(3, 4).magnitude() = {mag}") # normalize v_norm = v.normalize() print_test(f"Vector(3, 4).normalize() = ({v_norm.x:.3f}, {v_norm.y:.3f})") # dot product v_a = Vector(2, 3) v_b = Vector(4, 5) dot = v_a.dot(v_b) print_test(f"Vector(2, 3).dot(Vector(4, 5)) = {dot}") # distance_to dist = v_a.distance_to(v_b) print_test(f"Vector(2, 3).distance_to(Vector(4, 5)) = {dist:.3f}") # Operators print("\n Operators:") # Addition v_sum = v_a + v_b print_test(f"Vector(2, 3) + Vector(4, 5) = ({v_sum.x}, {v_sum.y})") # Subtraction v_diff = v_b - v_a print_test(f"Vector(4, 5) - Vector(2, 3) = ({v_diff.x}, {v_diff.y})") # Multiplication (scalar) v_mult = v_a * 2.5 print_test(f"Vector(2, 3) * 2.5 = ({v_mult.x}, {v_mult.y})") # Division (scalar) v_div = v_b / 2.0 print_test(f"Vector(4, 5) / 2.0 = ({v_div.x}, {v_div.y})") # Comparison v_eq1 = Vector(1, 2) v_eq2 = Vector(1, 2) v_neq = Vector(3, 4) print_test(f"Vector(1, 2) == Vector(1, 2) = {v_eq1 == v_eq2}") print_test(f"Vector(1, 2) != Vector(3, 4) = {v_eq1 != v_neq}") return True def test_frame_api(): """Test all Frame constructors and methods""" print_section("FRAME API TESTS") # Create a test scene mcrfpy.createScene("api_test") mcrfpy.setScene("api_test") ui = mcrfpy.sceneUI("api_test") # Constructor variants print("\n Constructors:") # Empty constructor f1 = Frame() print_test(f"Frame() - pos=({f1.x}, {f1.y}), size=({f1.w}, {f1.h})") ui.append(f1) # Position only f2 = Frame(100, 50) print_test(f"Frame(100, 50) - pos=({f2.x}, {f2.y}), size=({f2.w}, {f2.h})") ui.append(f2) # Position and size f3 = Frame(200, 100, 150, 75) print_test(f"Frame(200, 100, 150, 75) - pos=({f3.x}, {f3.y}), size=({f3.w}, {f3.h})") ui.append(f3) # Full constructor f4 = Frame(300, 200, 200, 100, fill_color=Color(100, 100, 200), outline_color=Color(255, 255, 0), outline=3) print_test("Frame with all parameters") ui.append(f4) # With click handler def on_click(x, y, button): print(f" Frame clicked at ({x}, {y}) with button {button}") f5 = Frame(500, 300, 100, 100, click=on_click) print_test("Frame with click handler") ui.append(f5) # Properties print("\n Properties:") # Position and size f = Frame(10, 20, 30, 40) print_test(f"Initial: x={f.x}, y={f.y}, w={f.w}, h={f.h}") f.x = 50 f.y = 60 f.w = 70 f.h = 80 print_test(f"Modified: x={f.x}, y={f.y}, w={f.w}, h={f.h}") # Colors f.fill_color = Color(255, 0, 0, 128) f.outline_color = Color(0, 255, 0) f.outline = 5.0 print_test(f"Colors set, outline={f.outline}") # Visibility and opacity f.visible = False f.opacity = 0.5 print_test(f"visible={f.visible}, opacity={f.opacity}") f.visible = True # Reset # Z-index f.z_index = 10 print_test(f"z_index={f.z_index}") # Children collection child1 = Frame(5, 5, 20, 20) child2 = Frame(30, 5, 20, 20) f.children.append(child1) f.children.append(child2) print_test(f"children.count = {len(f.children)}") # Clip children f.clip_children = True print_test(f"clip_children={f.clip_children}") # Methods print("\n Methods:") # get_bounds bounds = f.get_bounds() print_test(f"get_bounds() = {bounds}") # move old_pos = (f.x, f.y) f.move(10, 15) new_pos = (f.x, f.y) print_test(f"move(10, 15): {old_pos} -> {new_pos}") # resize old_size = (f.w, f.h) f.resize(100, 120) new_size = (f.w, f.h) print_test(f"resize(100, 120): {old_size} -> {new_size}") # Position tuple property f.pos = (150, 175) print_test(f"pos property: ({f.x}, {f.y})") # Children collection methods print("\n Children Collection:") # Clear and test f.children.extend([Frame(0, 0, 10, 10) for _ in range(3)]) print_test(f"extend() - count = {len(f.children)}") # Index access first_child = f.children[0] print_test(f"children[0] = Frame at ({first_child.x}, {first_child.y})") # Remove f.children.remove(first_child) print_test(f"remove() - count = {len(f.children)}") # Iteration count = 0 for child in f.children: count += 1 print_test(f"iteration - counted {count} children") return True def test_caption_api(): """Test all Caption constructors and methods""" print_section("CAPTION API TESTS") ui = mcrfpy.sceneUI("api_test") # Constructor variants print("\n Constructors:") # Empty constructor c1 = Caption() print_test(f"Caption() - text='{c1.text}', pos=({c1.x}, {c1.y})") ui.append(c1) # Text only c2 = Caption("Hello World") print_test(f"Caption('Hello World') - pos=({c2.x}, {c2.y})") ui.append(c2) # Text and position c3 = Caption("Positioned Text", 100, 50) print_test(f"Caption('Positioned Text', 100, 50)") ui.append(c3) # With font (would need Font object) # font = Font("assets/fonts/arial.ttf", 16) # c4 = Caption("Custom Font", 200, 100, font) # Full constructor c5 = Caption("Styled Text", 300, 150, fill_color=Color(255, 255, 0), outline_color=Color(255, 0, 0), outline=2) print_test("Caption with all style parameters") ui.append(c5) # With click handler def caption_click(x, y, button): print(f" Caption clicked at ({x}, {y})") c6 = Caption("Clickable", 400, 200, click=caption_click) print_test("Caption with click handler") ui.append(c6) # Properties print("\n Properties:") c = Caption("Test Caption", 10, 20) # Text c.text = "Modified Text" print_test(f"text = '{c.text}'") # Position c.x = 50 c.y = 60 print_test(f"position = ({c.x}, {c.y})") # Colors and style c.fill_color = Color(0, 255, 255) c.outline_color = Color(255, 0, 255) c.outline = 3.0 print_test("Colors and outline set") # Size (read-only, computed from text) print_test(f"size (computed) = ({c.w}, {c.h})") # Common properties c.visible = True c.opacity = 0.8 c.z_index = 5 print_test(f"visible={c.visible}, opacity={c.opacity}, z_index={c.z_index}") # Methods print("\n Methods:") # get_bounds bounds = c.get_bounds() print_test(f"get_bounds() = {bounds}") # move c.move(25, 30) print_test(f"move(25, 30) - new pos = ({c.x}, {c.y})") # Special text behaviors print("\n Text Behaviors:") # Empty text c.text = "" print_test(f"Empty text - size = ({c.w}, {c.h})") # Multiline text c.text = "Line 1\nLine 2\nLine 3" print_test(f"Multiline text - size = ({c.w}, {c.h})") # Very long text c.text = "A" * 100 print_test(f"Long text (100 chars) - size = ({c.w}, {c.h})") return True def test_sprite_api(): """Test all Sprite constructors and methods""" print_section("SPRITE API TESTS") ui = mcrfpy.sceneUI("api_test") # Try to load a texture for testing texture = None try: texture = Texture("assets/sprites/player.png", grid_size=(32, 32)) print_test("Texture loaded successfully") except: print_test("Texture load failed - using None", False) # Constructor variants print("\n Constructors:") # Empty constructor s1 = Sprite() print_test(f"Sprite() - pos=({s1.x}, {s1.y}), sprite_index={s1.sprite_index}") ui.append(s1) # Position only s2 = Sprite(100, 50) print_test(f"Sprite(100, 50)") ui.append(s2) # Position and texture s3 = Sprite(200, 100, texture) print_test(f"Sprite(200, 100, texture)") ui.append(s3) # Full constructor s4 = Sprite(300, 150, texture, sprite_index=5, scale=2.0) print_test(f"Sprite with texture, index=5, scale=2.0") ui.append(s4) # With click handler def sprite_click(x, y, button): print(f" Sprite clicked!") s5 = Sprite(400, 200, texture, click=sprite_click) print_test("Sprite with click handler") ui.append(s5) # Properties print("\n Properties:") s = Sprite(10, 20, texture) # Position s.x = 50 s.y = 60 print_test(f"position = ({s.x}, {s.y})") # Position tuple s.pos = (75, 85) print_test(f"pos tuple = ({s.x}, {s.y})") # Sprite index s.sprite_index = 10 print_test(f"sprite_index = {s.sprite_index}") # Scale s.scale = 1.5 print_test(f"scale = {s.scale}") # Size (computed from texture and scale) print_test(f"size (computed) = ({s.w}, {s.h})") # Texture s.texture = texture # Can reassign texture print_test("Texture reassigned") # Common properties s.visible = True s.opacity = 0.9 s.z_index = 3 print_test(f"visible={s.visible}, opacity={s.opacity}, z_index={s.z_index}") # Methods print("\n Methods:") # get_bounds bounds = s.get_bounds() print_test(f"get_bounds() = {bounds}") # move old_pos = (s.x, s.y) s.move(15, 20) new_pos = (s.x, s.y) print_test(f"move(15, 20): {old_pos} -> {new_pos}") # Sprite animation test print("\n Sprite Animation:") # Test different sprite indices for i in range(5): s.sprite_index = i print_test(f"Set sprite_index to {i}") return True def test_grid_api(): """Test all Grid constructors and methods""" print_section("GRID API TESTS") ui = mcrfpy.sceneUI("api_test") # Load texture for grid texture = None try: texture = Texture("assets/sprites/tiles.png", grid_size=(16, 16)) print_test("Tile texture loaded") except: print_test("Tile texture load failed", False) # Constructor variants print("\n Constructors:") # Empty constructor g1 = Grid() print_test(f"Grid() - pos=({g1.x}, {g1.y}), grid_size={g1.grid_size}") ui.append(g1) # Position only g2 = Grid(100, 50) print_test(f"Grid(100, 50)") ui.append(g2) # Position and grid size g3 = Grid(200, 100, grid_size=(30, 20)) print_test(f"Grid with size (30, 20)") ui.append(g3) # With texture g4 = Grid(300, 150, grid_size=(25, 15), texture=texture) print_test("Grid with texture") ui.append(g4) # Full constructor g5 = Grid(400, 200, grid_size=(20, 10), texture=texture, tile_width=24, tile_height=24, scale=1.5) print_test("Grid with all parameters") ui.append(g5) # With click handler def grid_click(x, y, button): print(f" Grid clicked at ({x}, {y})") g6 = Grid(500, 250, click=grid_click) print_test("Grid with click handler") ui.append(g6) # Properties print("\n Properties:") g = Grid(10, 20, grid_size=(40, 30)) # Position g.x = 50 g.y = 60 print_test(f"position = ({g.x}, {g.y})") # Grid dimensions print_test(f"grid_size = {g.grid_size}") print_test(f"grid_x = {g.grid_x}, grid_y = {g.grid_y}") # Tile dimensions g.tile_width = 20 g.tile_height = 20 print_test(f"tile size = ({g.tile_width}, {g.tile_height})") # Scale g.scale = 2.0 print_test(f"scale = {g.scale}") # Texture g.texture = texture print_test("Texture assigned") # Fill color g.fill_color = Color(30, 30, 50) print_test("Fill color set") # Camera properties g.center = (20.0, 15.0) print_test(f"center (camera) = {g.center}") g.zoom = 1.5 print_test(f"zoom = {g.zoom}") # Common properties g.visible = True g.opacity = 0.95 g.z_index = 1 print_test(f"visible={g.visible}, opacity={g.opacity}, z_index={g.z_index}") # Grid point access print("\n Grid Points:") # Access grid point point = g.at(5, 5) print_test(f"at(5, 5) returned GridPoint") # Modify grid point point.tilesprite = 10 point.tile_overlay = 2 point.walkable = False point.transparent = True point.color = Color(255, 0, 0, 128) print_test("GridPoint properties modified") # Check modifications print_test(f" tilesprite = {point.tilesprite}") print_test(f" walkable = {point.walkable}") print_test(f" transparent = {point.transparent}") # Entity collection print("\n Entity Collection:") # Create entities if texture: e1 = Entity(10.5, 10.5, texture, sprite_index=5) e2 = Entity(15.0, 12.0, texture, sprite_index=8) g.entities.append(e1) g.entities.append(e2) print_test(f"Added 2 entities, count = {len(g.entities)}") # Access entities first = g.entities[0] print_test(f"entities[0] at ({first.x}, {first.y})") # Iterate entities count = 0 for entity in g.entities: count += 1 print_test(f"Iterated {count} entities") # Methods print("\n Methods:") # get_bounds bounds = g.get_bounds() print_test(f"get_bounds() = {bounds}") # move g.move(20, 25) print_test(f"move(20, 25) - new pos = ({g.x}, {g.y})") # Points array access print("\n Points Array:") # The points property is a 2D array all_points = g.points print_test(f"points array dimensions: {len(all_points)}x{len(all_points[0]) if all_points else 0}") # Modify multiple points for y in range(5): for x in range(5): pt = g.at(x, y) pt.tilesprite = x + y * 5 pt.color = Color(x * 50, y * 50, 100) print_test("Modified 5x5 area of grid") return True def test_entity_api(): """Test all Entity constructors and methods""" print_section("ENTITY API TESTS") # Entities need to be in a grid ui = mcrfpy.sceneUI("api_test") # Create grid and texture texture = None try: texture = Texture("assets/sprites/entities.png", grid_size=(32, 32)) print_test("Entity texture loaded") except: print_test("Entity texture load failed", False) grid = Grid(50, 50, grid_size=(30, 30), texture=texture) ui.append(grid) # Constructor variants print("\n Constructors:") # Empty constructor e1 = Entity() print_test(f"Entity() - pos=({e1.x}, {e1.y}), sprite_index={e1.sprite_index}") grid.entities.append(e1) # Position only e2 = Entity(5.5, 3.5) print_test(f"Entity(5.5, 3.5)") grid.entities.append(e2) # Position and texture e3 = Entity(10.0, 8.0, texture) print_test("Entity with texture") grid.entities.append(e3) # Full constructor e4 = Entity(15.5, 12.5, texture, sprite_index=7, scale=1.5) print_test("Entity with all parameters") grid.entities.append(e4) # Properties print("\n Properties:") e = Entity(20.0, 15.0, texture, sprite_index=3) grid.entities.append(e) # Position (float coordinates in grid space) e.x = 22.5 e.y = 16.5 print_test(f"position = ({e.x}, {e.y})") # Position tuple e.position = (24.0, 18.0) print_test(f"position tuple = {e.position}") # Sprite index e.sprite_index = 12 print_test(f"sprite_index = {e.sprite_index}") # Scale e.scale = 2.0 print_test(f"scale = {e.scale}") # Methods print("\n Methods:") # index() - get position in entity collection idx = e.index() print_test(f"index() in collection = {idx}") # Gridstate (visibility per grid cell) print("\n Grid State:") # Access gridstate if len(e.gridstate) > 0: state = e.gridstate[0] print_test(f"gridstate[0] - visible={state.visible}, discovered={state.discovered}") # Modify visibility state.visible = True state.discovered = True print_test("Modified gridstate visibility") # at() method - check if entity occupies a grid point # This would need a GridPointState object # occupied = e.at(some_gridpoint_state) # die() method - remove from grid print("\n Entity Lifecycle:") # Create temporary entity temp_entity = Entity(25.0, 25.0, texture) grid.entities.append(temp_entity) count_before = len(grid.entities) # Remove it temp_entity.die() count_after = len(grid.entities) print_test(f"die() - entity count: {count_before} -> {count_after}") # Entity movement print("\n Entity Movement:") # Test fractional positions (entities can be between grid cells) e.position = (10.0, 10.0) print_test(f"Integer position: {e.position}") e.position = (10.5, 10.5) print_test(f"Center of cell: {e.position}") e.position = (10.25, 10.75) print_test(f"Fractional position: {e.position}") return True def test_collections(): """Test UICollection and EntityCollection behaviors""" print_section("COLLECTION API TESTS") ui = mcrfpy.sceneUI("api_test") # Test UICollection (scene UI and frame children) print("\n UICollection (Scene UI):") # Clear scene while len(ui) > 0: ui.remove(ui[0]) print_test(f"Cleared - length = {len(ui)}") # append f1 = Frame(10, 10, 50, 50) ui.append(f1) print_test(f"append() - length = {len(ui)}") # extend frames = [Frame(x * 60, 10, 50, 50) for x in range(1, 4)] ui.extend(frames) print_test(f"extend() with 3 items - length = {len(ui)}") # index access item = ui[0] print_test(f"ui[0] = Frame at ({item.x}, {item.y})") # slice access slice_items = ui[1:3] print_test(f"ui[1:3] returned {len(slice_items)} items") # index() method idx = ui.index(f1) print_test(f"index(frame) = {idx}") # count() method cnt = ui.count(f1) print_test(f"count(frame) = {cnt}") # in operator contains = f1 in ui print_test(f"frame in ui = {contains}") # iteration count = 0 for item in ui: count += 1 print_test(f"Iteration counted {count} items") # remove ui.remove(f1) print_test(f"remove() - length = {len(ui)}") # Test Frame.children collection print("\n UICollection (Frame Children):") parent = Frame(100, 100, 300, 200) ui.append(parent) # Add children child1 = Caption("Child 1", 10, 10) child2 = Caption("Child 2", 10, 30) child3 = Frame(10, 50, 50, 50) parent.children.append(child1) parent.children.append(child2) parent.children.append(child3) print_test(f"Added 3 children - count = {len(parent.children)}") # Mixed types in collection has_caption = any(isinstance(child, Caption) for child in parent.children) has_frame = any(isinstance(child, Frame) for child in parent.children) print_test(f"Mixed types: has Caption = {has_caption}, has Frame = {has_frame}") # Test EntityCollection print("\n EntityCollection (Grid Entities):") texture = None try: texture = Texture("assets/sprites/entities.png", grid_size=(32, 32)) except: pass grid = Grid(400, 100, grid_size=(20, 20), texture=texture) ui.append(grid) # Add entities entities = [] for i in range(5): e = Entity(float(i * 2), float(i * 2), texture, sprite_index=i) grid.entities.append(e) entities.append(e) print_test(f"Added 5 entities - count = {len(grid.entities)}") # Access and iteration first_entity = grid.entities[0] print_test(f"entities[0] at ({first_entity.x}, {first_entity.y})") # Remove entity grid.entities.remove(first_entity) print_test(f"Removed entity - count = {len(grid.entities)}") return True def test_animation_api(): """Test Animation class API""" print_section("ANIMATION API TESTS") ui = mcrfpy.sceneUI("api_test") # Import Animation from mcrfpy import Animation print("\n Animation Constructors:") # Basic animation anim1 = Animation("x", 100.0, 2.0) print_test("Animation('x', 100.0, 2.0)") # With easing anim2 = Animation("y", 200.0, 3.0, "easeInOut") print_test("Animation with easing='easeInOut'") # Delta mode anim3 = Animation("w", 50.0, 1.5, "linear", delta=True) print_test("Animation with delta=True") # Color animation anim4 = Animation("fill_color", Color(255, 0, 0), 2.0) print_test("Animation with Color target") # Vector animation anim5 = Animation("position", (10.0, 20.0), 2.5, "easeOutBounce") print_test("Animation with position tuple") # Sprite sequence anim6 = Animation("sprite_index", [0, 1, 2, 3, 2, 1], 2.0) print_test("Animation with sprite sequence") # Properties print("\n Animation Properties:") # Check properties print_test(f"property = '{anim1.property}'") print_test(f"duration = {anim1.duration}") print_test(f"elapsed = {anim1.elapsed}") print_test(f"is_complete = {anim1.is_complete}") print_test(f"is_delta = {anim3.is_delta}") # Methods print("\n Animation Methods:") # Create test frame frame = Frame(50, 50, 100, 100) frame.fill_color = Color(100, 100, 100) ui.append(frame) # Start animation anim1.start(frame) print_test("start() called on frame") # Get current value (before update) current = anim1.get_current_value() print_test(f"get_current_value() = {current}") # Manual update (usually automatic) anim1.update(0.5) # 0.5 seconds print_test("update(0.5) called") # Check elapsed time print_test(f"elapsed after update = {anim1.elapsed}") # All easing functions print("\n Available Easing Functions:") easings = [ "linear", "easeIn", "easeOut", "easeInOut", "easeInQuad", "easeOutQuad", "easeInOutQuad", "easeInCubic", "easeOutCubic", "easeInOutCubic", "easeInQuart", "easeOutQuart", "easeInOutQuart", "easeInSine", "easeOutSine", "easeInOutSine", "easeInExpo", "easeOutExpo", "easeInOutExpo", "easeInCirc", "easeOutCirc", "easeInOutCirc", "easeInElastic", "easeOutElastic", "easeInOutElastic", "easeInBack", "easeOutBack", "easeInOutBack", "easeInBounce", "easeOutBounce", "easeInOutBounce" ] # Test creating animation with each easing for easing in easings[:10]: # Test first 10 try: test_anim = Animation("x", 100.0, 1.0, easing) print_test(f"Easing '{easing}' ✓") except: print_test(f"Easing '{easing}' failed", False) return True def test_scene_api(): """Test scene-related API functions""" print_section("SCENE API TESTS") print("\n Scene Management:") # Create scene mcrfpy.createScene("test_scene_1") print_test("createScene('test_scene_1')") mcrfpy.createScene("test_scene_2") print_test("createScene('test_scene_2')") # Set active scene mcrfpy.setScene("test_scene_1") print_test("setScene('test_scene_1')") # Get scene UI ui1 = mcrfpy.sceneUI("test_scene_1") print_test(f"sceneUI('test_scene_1') - collection size = {len(ui1)}") ui2 = mcrfpy.sceneUI("test_scene_2") print_test(f"sceneUI('test_scene_2') - collection size = {len(ui2)}") # Add content to scenes ui1.append(Frame(10, 10, 100, 100)) ui1.append(Caption("Scene 1", 10, 120)) print_test(f"Added content to scene 1 - size = {len(ui1)}") ui2.append(Frame(20, 20, 150, 150)) ui2.append(Caption("Scene 2", 20, 180)) print_test(f"Added content to scene 2 - size = {len(ui2)}") # Scene transitions print("\n Scene Transitions:") # Note: Actual transition types would need to be tested visually # TransitionType enum: None, Fade, SlideLeft, SlideRight, SlideUp, SlideDown # Keypress handling print("\n Input Handling:") def test_keypress(scene_name, keycode): print(f" Key pressed in {scene_name}: {keycode}") mcrfpy.keypressScene("test_scene_1", test_keypress) print_test("keypressScene() handler registered") return True def test_audio_api(): """Test audio-related API functions""" print_section("AUDIO API TESTS") print("\n Sound Functions:") # Create sound buffer try: mcrfpy.createSoundBuffer("test_sound", "assets/audio/click.wav") print_test("createSoundBuffer('test_sound', 'click.wav')") # Play sound mcrfpy.playSound("test_sound") print_test("playSound('test_sound')") # Set volume mcrfpy.setVolume("test_sound", 0.5) print_test("setVolume('test_sound', 0.5)") except Exception as e: print_test(f"Audio functions failed: {e}", False) return True def test_timer_api(): """Test timer API functions""" print_section("TIMER API TESTS") print("\n Timer Functions:") # Timer callback def timer_callback(runtime): print(f" Timer fired at runtime: {runtime}") # Set timer mcrfpy.setTimer("test_timer", timer_callback, 1000) # 1 second print_test("setTimer('test_timer', callback, 1000)") # Delete timer mcrfpy.delTimer("test_timer") print_test("delTimer('test_timer')") # Multiple timers mcrfpy.setTimer("timer1", lambda r: print(f" Timer 1: {r}"), 500) mcrfpy.setTimer("timer2", lambda r: print(f" Timer 2: {r}"), 750) mcrfpy.setTimer("timer3", lambda r: print(f" Timer 3: {r}"), 1000) print_test("Set 3 timers with different intervals") # Clean up mcrfpy.delTimer("timer1") mcrfpy.delTimer("timer2") mcrfpy.delTimer("timer3") print_test("Cleaned up all timers") return True def test_edge_cases(): """Test edge cases and error conditions""" print_section("EDGE CASES AND ERROR HANDLING") ui = mcrfpy.sceneUI("api_test") print("\n Boundary Values:") # Negative positions f = Frame(-100, -50, 50, 50) print_test(f"Negative position: ({f.x}, {f.y})") # Zero size f2 = Frame(0, 0, 0, 0) print_test(f"Zero size: ({f2.w}, {f2.h})") # Very large values f3 = Frame(10000, 10000, 5000, 5000) print_test(f"Large values: pos=({f3.x}, {f3.y}), size=({f3.w}, {f3.h})") # Opacity bounds f.opacity = -0.5 print_test(f"Opacity below 0: {f.opacity}") f.opacity = 2.0 print_test(f"Opacity above 1: {f.opacity}") # Color component bounds c = Color(300, -50, 1000, 128) print_test(f"Color out of bounds: ({c.r}, {c.g}, {c.b}, {c.a})") print("\n Empty Collections:") # Empty children frame = Frame(0, 0, 100, 100) print_test(f"Empty children collection: {len(frame.children)}") # Access empty collection try: item = frame.children[0] print_test("Accessing empty collection[0]", False) except IndexError: print_test("Accessing empty collection[0] raises IndexError") print("\n Invalid Operations:") # Grid without texture g = Grid(0, 0, grid_size=(10, 10)) point = g.at(5, 5) point.tilesprite = 10 # No texture to reference print_test("Set tilesprite without texture") # Entity without grid e = Entity(5.0, 5.0) # e.die() would fail if not in a grid print_test("Created entity without grid") return True def run_all_tests(): """Run all API tests""" print("\n" + "="*60) print(" McRogueFace Exhaustive API Test Suite") print(" Testing every constructor and method...") print("="*60) # Run each test category test_functions = [ test_color_api, test_vector_api, test_frame_api, test_caption_api, test_sprite_api, test_grid_api, test_entity_api, test_collections, test_animation_api, test_scene_api, test_audio_api, test_timer_api, test_edge_cases ] passed = 0 failed = 0 for test_func in test_functions: try: if test_func(): passed += 1 else: failed += 1 except Exception as e: print(f"\n ERROR in {test_func.__name__}: {e}") failed += 1 # Summary print("\n" + "="*60) print(f" TEST SUMMARY: {passed} passed, {failed} failed") print("="*60) # Visual test scene print("\n Visual elements are displayed in the 'api_test' scene.") print(" The test is complete. Press ESC to exit.") def handle_exit(scene_name, keycode): """Handle ESC key to exit""" if keycode == 256: # ESC print("\nExiting API test suite...") sys.exit(0) # Set up exit handler mcrfpy.keypressScene("api_test", handle_exit) # Run after short delay to ensure scene is ready def start_tests(runtime): run_all_tests() mcrfpy.setTimer("start_tests", start_tests, 100) print("Starting McRogueFace Exhaustive API Demo...") print("This will test EVERY constructor and method.") print("Press ESC to exit at any time.")