# Sprint 11a — TDD Plan

Testing framework: **pytest** with **pytest-asyncio** (`asyncio_mode = "auto"`).
Test location: `tests/test_tools/` for bridge tools, `tests/test_bridge/` for bridge-level tests.
Mocking: Bridge is mocked via `unittest.mock.AsyncMock` on `bridge.request()`.
Existing patterns: See `tests/test_tools/conftest.py` for fixtures and `tests/test_tools/test_build_scene.py` for bridge mock examples.

---

## Section 1: Fix _handle_run — Reliable Scene Launch

**No Python-side tests** — the _handle_run changes are in GDScript which runs inside Godot. The GDScript handler changes are validated manually.

However, the `run.py` return value change (pass through bridge response) affects tests:

```python
# Test: run(action="play") returns bridge response dict (not locally constructed)
# Test: run(action="stop") still returns {"action": "stop"}
# Test: run(action="play") passes scene param to bridge
```

---

## Section 2: Script Reload Handler + script_ops Integration

### test_script_ops_reload.py

```python
# Test: _try_reload_script calls bridge.request("reload_script") for .gd files
# Test: _try_reload_script constructs correct res:// path from rel_path
# Test: _try_reload_script does NOT call bridge for .tres files
# Test: _try_reload_script does NOT call bridge for .tscn files
# Test: _try_reload_script silently skips when get_bridge_or_none returns None
# Test: _try_reload_script silently skips when bridge.request raises exception
# Test: _op_write calls _try_reload_script after writing .gd file
# Test: _op_create calls _try_reload_script after creating .gd file
# Test: _op_write does NOT call _try_reload_script for non-.gd files
# Test: _op_patch does NOT call _try_reload_script (patches don't create new files)
```

---

## Section 3: build_scene Response Enhancement

**No Python-side tests needed** — the node_names addition is in GDScript. The Python `build_scene.py` passes through the bridge response unchanged. Existing tests for build_scene validation logic remain unaffected.

---

## Section 4: set_main_scene Handler

**No Python-side tests** — the handler is GDScript-only. No new Python MCP tool is created.

---

## Section 5: Adaptive Timeout in run.py

### test_run_adaptive_timeout.py

```python
# Test: timeout auto-detects from GLB count — 0 GLB files → 10.0s
# Test: timeout auto-detects — 60 GLB files → 15.0s
# Test: timeout auto-detects — 120 GLB files → 20.0s
# Test: explicit timeout > 0 overrides auto-detection
# Test: missing GODOTIQ_PROJECT_ROOT env var → 15.0s default
# Test: bridge.request receives timeout kwarg = computed_timeout + 5
# Test: bridge.request receives params with timeout = computed_timeout (for GDScript)
# Test: action="stop" does not compute adaptive timeout
```

Mock setup: Use `tmp_path` to create directories with varying numbers of `.glb` files. Patch `os.environ` to set `GODOTIQ_PROJECT_ROOT`.

---

## Section 6: verify_motion Tool

### test_verify_motion.py

```python
# Test: returns MOVING when property value changes between inspections
# Test: returns STATIC when property value stays same
# Test: uses correct property_name in state_inspect queries
# Test: respects custom duration parameter
# Test: returns error when game is not running (ping shows game_running=false)
# Test: returns ERROR verdict when second state_inspect fails
# Test: first state_inspect failure returns error without sleeping
# Test: default property_name is "position"
# Test: default duration is 2.0
```

Mock setup: Mock `bridge.request` to return different state_inspect results for first and second calls. Use `unittest.mock.patch("asyncio.sleep")` to avoid actual delays.

---

## Section 7: Fresh MCP Prompt

**No tests** — this is a documentation file. Validation is manual review of content completeness.
