# lib-core.camera-test Test-lib for `lib-core.camera` (Tests-as-Libs per ADR-0037). **Version:** 0.1.0 **Lib-ID:** lib-core.camera-test **Requires:** lib-core.camera v>=0.3.0, lib-core.input v>=0.4.0 **Tags:** test, camera ## Topology ```mermaid graph LR this["lib-core.camera-test"] lib_core_camera["lib-core.camera"] this --> lib_core_camera lib_core_input["lib-core.input"] this --> lib_core_input engine["engine.*"] this --> engine ``` ## Coverage Statement Per Fault-Injection-Audit-Convention (2026-05-16): | Section | Assertion-Count | Coverage | |---|---|---| | State setters/getters | 3 | `set_target`/`target`, `set_zoom`/`zoom`, `set_pan_speed`/`pan_speed` | | Bounds-Clamping | 3 | `set_bounds` clamping, `clear_bounds` -> unclamped, immediate-clamp on bounds-shrink | | pan_enabled state | 6 | Per-source disable (keys/edge/drag), `bind_pan_keys` auto-enable, toggle false/true | | pan_invert state | 2 | `set_pan_invert(false)`, `set_pan_invert(true)` | | Engine-Surface existence | 2 | `engine.input.get_mouse_delta`, `engine.window.size` function presence | | **TOTAL** | **16** | | ### Tested-Surface - `camera.set_target` / `camera.target` (value + bounds-clamping) - `camera.set_zoom` / `camera.zoom` - `camera.set_pan_speed` / `camera.pan_speed` - `camera.set_bounds`, `camera.clear_bounds` - `camera.bind_pan_keys` (auto-enable side-effect) - `camera.set_pan_enabled` / `camera.pan_enabled` (toggle false/true) - `camera.set_pan_invert` / `camera.pan_invert` - Engine surface: `engine.input.get_mouse_delta`, `engine.window.size` ### Fault-Injection Audit (2026-05-16) Verified via deliberate-mutation in fixture-mirror; mutations reverted after observation. | # | Mutation | Caught by | |---|---|---| | M1 | `set_target`: x/y assignments swapped | Assertions 1 (`set_target -> target`) + 4 (`set_target clamped to bounds`) fail | | M2 | `clear_bounds` made no-op | Assertion 5 (`clear_bounds -> unclamped`) fails | | M3 | `bind_pan_keys` auto-enable removed | Assertion 10 (`bind_pan_keys auto-enables`) fails | All 3 mutations caught — no gaps detected. ### Structurally Untestable - `camera.begin` / `camera.finish` — render-stack side-effects only observable inside a render hook; headless test-runner has no render context. - `camera.update(dt)` interaction with per-frame mouse-input — requires live `engine.input` polling state. - `camera.screen_to_world` — requires live window-size from `engine.window.size`, headless returns 0 (deferred). ### Deferred - `enable_pan_edge`, `bind_pan_drag` runtime behavior (covered indirectly via `pan_enabled` toggles). - `set_edge_threshold` / `edge_threshold` getter/setter pair. ## Running Via `--test-libs=lib-core.camera-test` (Smoke P0-S-batch Stage): ```bash Sporel.exe --libs-dir= --test-libs=lib-core.camera-test ``` Output is TAP version 13 on stdout; exit-code = failure-count (0 = all pass). ## References - ADR-0037 (Tests-as-Libs Convention) - ADR-0038 (API-Doc-Convention) - Production-Lib: `~/Projects/Sporel/sporel-libs/lib-core/camera/README.md` - Spec: `meta/docs/superpowers/specs/2026-05-13-p3-5-camera-free-pan-design.md`