Prompt file imported from iwooden/rss-az (
.claude/commands/phase-test.md). Fill in{{arguments}}before use. Copyright stays with the author.
Implement tests for the {{arguments}} phase in tests/phases/.
Setup
- Read the phase implementation:
phases/{{arguments}}.pyxandphases/{{arguments}}.pxd. Understand every code path, branch, and edge case. - Read the corresponding action enumerator in
core/actions.pyx— search for_enumerate_{{arguments}}or the relevantDPHASE_*constant. Understand which actions are legal and when. - Read the shared test infrastructure in
tests/phases/conftest.py. Understand every fixture and helper available — you MUST reuse them. Do not duplicate logic that already exists there. - Read the old tests on
mainfor guidance on edge cases (NOT for code to copy):git show main:tests/phases/test_{{arguments}}.py 2>/dev/null. The old tests may use a completely different API — extract only the test ideas (what scenarios matter, what boundaries to check). - Read
RULES.mdfor the rules governing this phase — understand the game logic you're testing.
Architecture rules
- Reuse
conftest.pyfixtures and helpers.game_state,float_corp_for_test,setup_receivership_corp,apply_and_verify,assert_invariants,get_legal_actions,find_legal_action— use them. If you need a new fixture or helper that would benefit multiple test files, add it toconftest.py, not to the test file. - No method-level imports. All imports at file scope, top of file. No exceptions.
- No code duplication. If you find yourself writing the same setup logic in multiple tests, extract it into a fixture or helper (in conftest.py if reusable, as a module-level helper in the test file if phase-specific).
- Test through the driver. Use
apply_and_verify(state, action_id)which callsDRIVER.apply_action()and checks invariants on every intermediate state. Do NOT call phase-internalcdeffunctions directly. The_pywrappers on some phases exist for ad-hoc debugging, not for tests — the driver is the contract. - Scope tests to the phase under test. Phase tests should only test logic within the specific phase and its transition to the next phase. Do NOT transit through earlier phases to reach the phase under test — instead, set up state directly and call the phase's
setup_*_phase_py()entry point. This avoids coupling to other phases' side effects and keeps tests focused. - Use
find_legal_actionto locate actions. Don't hardcode action IDs. Usefind_legal_action(state, action_type=..., corp_id=..., company_id=..., amount=...)to find the right action by its decoded semantics. - Use
get_legal_actionsto inspect the full legal set. Returns list of(action_id, decoded_info)tuples for the current state. - Encode action IDs when the mapping is simple. For phases with trivial encoding (e.g., CLOSING where action 0 = pass, action N = close company N), you can construct action IDs directly using the encode helpers from
core.actions— but preferfind_legal_actionfor complex encodings. - Use existing entity APIs and constants. If the task needs a missing accessor or semantic mutation, extend the owning entity API and preserve its cache and ownership invariants. Avoid temporary state mutations or hardcoded constants as test workarounds.
What to test
Coverage targets
- Happy path: Each distinct action type the phase supports (pass, buy, sell, raise, close, etc.)
- State mutations: Verify the action correctly modifies state (cash changes, share transfers, phase transitions, entity ownership changes, etc.)
- Phase transitions: Verify the phase correctly transitions to the next phase when done (all corps processed, all players passed, etc.)
- Forced actions: If the phase has auto-applied forced actions (receivership corps, single legal action), verify they chain correctly through the driver.
- Boundary conditions: Test at exact thresholds (cash == cost, exactly 0 income, last company/corp, etc.)
- Enumeration correctness: Verify that the set of legal actions matches expectations for key scenarios (e.g., which companies are closable, which corps can issue, which par prices are valid).
What NOT to test
- Don't test invariants directly —
apply_and_verifyalready checksassert_invariantson every intermediate and final state. - Don't test action encoding/decoding — that's
core/actions's concern. - Don't test other phases' logic (e.g., don't test that INCOME works correctly inside a CLOSING test — just verify the phase transition happens).
- Don't write tests for scenarios that can't arise in legal play.
Style
- Use
pytestclasses to group related tests (e.g.,TestPassAction,TestBuyShare,TestPhaseTransition). - Descriptive method names:
test_close_company_removes_from_game, nottest_close_1. - Keep each test focused on ONE behavior. Multiple related assertions in one test are fine; testing two unrelated behaviors is not.
- Minimal state setup — use fixtures and helpers, then make the smallest possible mutation to reach the scenario under test.
- Include a brief docstring on tests where the scenario isn't obvious from the name.
File structure
Write the test file to tests/phases/test_{{arguments}}.py. If you need new shared fixtures or helpers, add them to tests/phases/conftest.py.
Verification
After writing the tests, run them:
.venv/bin/python -m pytest tests/phases/test_{{arguments}}.py -v 2>&1 | tail -60
Investigate failures against RULES.md and the intended behavior. Fix failures within the task's scope and report unrelated failures with enough detail to reproduce them. See AGENTS.md for repository guidance.
