Three documentation-adjacent defects, found while auditing what the July bugfix
batch obliged the docs to say.
#378 -- init_python_with_config(), the init path main.cpp actually uses, did no
pre-initialization at all. PyPreConfig.utf8_mode was never enabled, so the
filesystem encoding fell back to ASCII while sys.getdefaultencoding() and the
locale both reported UTF-8. open() with no explicit encoding= therefore could not
read a UTF-8 file:
open("notes.py").read()
# UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2
In any normal CPython 3, open() defaults to UTF-8. This broke any script reading a
data file, a save file, or its own source. init_python() -- the other init path --
had always set utf8_mode = 1; only the live path was missing it.
This also corrects the long-standing folklore that "--exec scripts must be
ASCII-only". They need not be, and never did: the C++ side reads the file and hands
the bytes to Python, which parses them as UTF-8 per PEP 3120. The folklore was
pointing at open(), via harnesses that read scripts themselves.
--run-forever (#350) parsed but was absent from print_help(), which lists every
other McRogueFace flag. The only place a user could learn it existed was the
runtime error printed after their script had already failed. CLI flags are not in
the API manifest, so nothing flagged the omission.
mcrfpy.step()'s docstring still read "Advance simulation time" -- accurate until
|
||
|---|---|---|
| .. | ||
| 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)