UIEntity now depends on the grid DATA layer only: - GridData gains cell_width_px/cell_height_px (mirrored from the grid texture in UIGrid's 5-arg ctor; texture is write-once) so entity tile<->pixel math no longer reaches into rendering (getTexture()). - GridData gains markDirty()/markCompositeDirty(): set the flag on the UIGrid subobject AND notify owning_view, covering both render paths. UIGrid disambiguates via 'using UIDrawable::markDirty' so all pre-existing UIGrid-receiver calls resolve exactly as before. - The three Python wrappers that still need the full UIGrid (GridPoint from entity.at(), the _GridData fallback in get_grid, find_path's temp wrapper) reconstruct it via a single aliasing-downcast helper (grid_as_uigrid) that documents the never-independently-allocated GridData invariant; init/set_grid simplify (share grid_data directly). Removing the casts is deferred to #252. entity.texture (new, frozen surface +1): thin get/set over the entity's own UISprite. Entities render with their OWN texture (default_texture fallback at construction); the grid's texture only determines cell size. Setter preserves sprite_index; rejects non-Texture (TypeError), null-data Texture wrappers (ValueError), and deletion. Adversarial review fixes folded in: - set_texture/get_texture guard uninitialized Entity wrappers (RuntimeError), isinstance errors, and null-data Textures. - PyUIGridViewType tp_dealloc no longer unconditionally severs GridData::owning_view: gated on last-owner (#251 use_count pattern) plus owning-view identity. Previously ANY Grid wrapper GC while the view lived (e.g. scene.children.append(mcrfpy.Grid(...))) silently broke entity.grid -> Grid identity and data-layer dirty notification. Tests: tests/regression/issue_313_entity_grid_data_test.py (texture semantics, grid-cell-size invariance, entity.grid identity, #251 gate survival, GridPoint outliving teardown, review-fix guards, owning_view survival) + tests/unit/entity_texture_test.py. API snapshot golden re-baselined: exactly +1 surface line (Entity.texture) + writability probe flip. Docs/stubs regenerated. Native + Emscripten builds verified. Known edges recorded in docs/api-audit-2026-04.md: texture read-back is a fresh wrapper each get (no Texture __eq__); sprite_index not re-validated against a new atlas. Multi-view markDirty broadcast and pure-GridData wrappers remain deferred to #252. Addresses #314. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| api | ||
| benchmarks | ||
| cookbook | ||
| demo | ||
| docs | ||
| fixtures | ||
| fuzz | ||
| geometry_demo | ||
| integration | ||
| notes | ||
| procgen_interactive | ||
| regression | ||
| snapshots | ||
| unit | ||
| vllm_demo | ||
| all_inputs.py | ||
| conftest.py | ||
| debug_viewport.py | ||
| gui.py | ||
| KNOWN_ISSUES.md | ||
| procgen_cave2_visualization.py | ||
| procgen_cave_visualization.py | ||
| pytest.ini | ||
| README.md | ||
| run_procgen_interactive.py | ||
| run_tests.py | ||
| shader_poc_test.py | ||
| shader_toggle_test.py | ||
| test_mcrogueface.py | ||
| wiki_api_verify.py | ||
| wiki_phase_d2_verify.py | ||
| wiki_phase_d3_verify.py | ||
| wiki_phase_d_verify.py | ||
| wiki_snippets_verify.py | ||
McRogueFace Test Suite
Automated tests for the McRogueFace game engine.
Directory Structure
tests/
├── unit/ # Unit tests for individual components (155+ tests)
├── integration/ # Integration tests for system interactions
├── regression/ # Bug regression tests (issue_XX_*.py)
├── benchmarks/ # Performance benchmarks
├── demo/ # Interactive demo system
│ ├── demo_main.py # Demo runner
│ └── screens/ # Per-feature demo screens
├── conftest.py # Pytest configuration and fixtures
├── pytest.ini # Pytest settings
├── run_tests.py # Standalone test runner
└── KNOWN_ISSUES.md # Test status and mcrfpy.step() documentation
Running Tests
With pytest (recommended)
# Run all tests
pytest tests/ -v
# Run specific directory
pytest tests/unit/ -v
# Run tests matching a pattern
pytest tests/ -k "bsp" -v
# Quick run with short timeout (some timeouts expected)
pytest tests/ -q --mcrf-timeout=5
# Full run with longer timeout
pytest tests/ -q --mcrf-timeout=30
# Stop on first failure
pytest tests/ -x
With run_tests.py
# Run all tests
python3 tests/run_tests.py
# Run specific category
python3 tests/run_tests.py unit
python3 tests/run_tests.py regression
# Verbose output
python3 tests/run_tests.py -v
# Quiet (no checksums)
python3 tests/run_tests.py -q
# Custom timeout
python3 tests/run_tests.py --timeout=30
Running individual tests
cd build
./mcrogueface --headless --exec ../tests/unit/some_test.py
Writing Tests
Test Pattern: Synchronous with mcrfpy.step()
Recommended: Use mcrfpy.step(t) to advance simulation time synchronously.
import mcrfpy
import sys
# Setup
scene = mcrfpy.Scene("test")
scene.activate()
# Create UI elements
frame = mcrfpy.Frame(pos=(100, 100), size=(50, 50))
scene.children.append(frame)
# Start animation
frame.animate("x", 500.0, 1.0, mcrfpy.Easing.LINEAR)
# Advance simulation synchronously
mcrfpy.step(1.5)
# Verify results
if abs(frame.x - 500.0) < 0.1:
print("PASS")
sys.exit(0)
else:
print(f"FAIL: frame.x = {frame.x}, expected 500.0")
sys.exit(1)
Test Pattern: Timer-based (legacy)
For tests that need multiple timer callbacks or complex timing:
import mcrfpy
import sys
def run_test(runtime):
# Test code here
print("PASS")
sys.exit(0)
scene = mcrfpy.Scene("test")
scene.activate()
# Timer fires after 100ms
timer = mcrfpy.Timer("test", run_test, 100)
# Script ends, game loop runs timer
Test Output
- Print
PASSandsys.exit(0)for success - Print
FAILwith details andsys.exit(1)for failure - Tests that timeout are marked as failures
Test Categories
Unit Tests (unit/)
Test individual components in isolation:
*_test.py- Standard component testsapi_*_test.py- Python API testsautomation_*_test.py- Automation module tests
Regression Tests (regression/)
Tests for specific bug fixes, named by issue number:
issue_XX_description_test.py
Integration Tests (integration/)
Tests for system interactions and complex scenarios.
Benchmarks (benchmarks/)
Performance measurement tests.
Demo (demo/)
Interactive demonstrations of features. Run with:
cd build
./mcrogueface ../tests/demo/demo_main.py
Tips
- Read tests as examples: Tests show correct API usage
- Use
mcrfpy.step(): Avoids timeout issues, makes tests deterministic - Check KNOWN_ISSUES.md: Documents expected failures and workarounds
- Screenshots: Use
mcrfpy.automation.screenshot("name.png")aftermcrfpy.step()
See Also
KNOWN_ISSUES.md- Current test status and themcrfpy.step()patternconftest.py- Pytest fixtures and custom collectordemo/screens/- Feature demonstrations (good API examples)