Test-lib README now declares its public surface (M.run_tests) so the doc-convention lint passes structural validation. Brings parity with maps-test which already has this section. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
lib-core.input-test
Test-lib for lib-core.input (Tests-as-Libs per ADR-0037).
Version: 0.1.0
Lib-ID: lib-core.input-test
Requires: lib-core.input v>=0.4.0
Tags: test, input
Topology
graph LR
this["lib-core.input-test"]
lib_core_input["lib-core.input"]
this --> lib_core_input
engine["engine.*"]
this --> engine
API
run_tests(ctx)
Syntax: M.run_tests(ctx) -> void
Description: Test-runner entrypoint. Executes 17 assertions against
lib-core.input. Called automatically by the engine's
--test-libs= orchestrator. Exits via engine.exit(engine.test.failures()).
Coverage Statement
Per Fault-Injection-Audit-Convention (2026-05-16):
| Section | Assertion-Count | Coverage |
|---|---|---|
| Engine surface presence | 7 | MOUSE_LEFT/RIGHT/MIDDLE constants, is_mouse_down, was_mouse_pressed, was_released, was_mouse_released |
bind mouse-strings |
1 | action_count == 1 after bind("click", {"mouse_left"}) |
bind mixed key+mouse |
1 | action_count == 2 after mixed bind {"e", "mouse_left"} |
bind rejects unknown mouse-name |
3 | Lua error raised, message mentions bad string, no partial state mutation |
| Headless query stubs | 4 | is_action_down, was_action_pressed, was_action_released return false; was_action_released for unknown returns false |
| Key-only regression | 1 | bind("walk_left", {"a","left"}) still works after BIND_MAP refactor |
| TOTAL | 17 |
Tested-Surface
input.bind(mouse-string acceptance, mixed key+mouse, unknown-name rejection, atomicity)input.action_countinput.is_action_down(bound action headless = false)input.was_action_pressedinput.was_action_released(bound action headless = false; unknown action = false)- Engine surface:
MOUSE_LEFT/RIGHT/MIDDLE,is_mouse_down,was_mouse_pressed,was_released,was_mouse_releasedfunction presence
Fault-Injection Audit (2026-05-16)
Verified via deliberate-mutation in fixture-mirror; mutations reverted after observation.
Caught Mutations
| # | Mutation | Caught by |
|---|---|---|
| M1 | function M.was_action_released renamed (API-break) |
Runtime error "attempt to call a nil value (field 'was_action_released')" — test aborts after assertion 14 |
| M2 | if not entries then return false end changed to return nil |
was_action_released for unknown action returns false fails (not ok, got nil) |
Uncaught Mutations (Gaps)
| # | Mutation | Why uncaught | Severity |
|---|---|---|---|
| M3 | Dispatch-swap in was_action_released for-loop (key-kind ↔ mouse-kind) |
Headless: all input queries return false regardless of swapped dispatch — no real events differentiate the paths | Med |
Resolution: Headless-unreachable. Requires real key/mouse events. Future-Slice B: integration test with simulated input events. No cheap headless fill possible.
Structurally Untestable
- Real keyboard/mouse event delivery — headless mode never produces input events.
was_action_releaseddispatch correctness for key-kind vs mouse-kind binding — see Gap M3.
Deferred
- Integration test with simulated input events (Future-Slice B).
Running
Via --test-libs=lib-core.input-test (Smoke P0-S-batch Stage):
Sporel.exe --libs-dir=<libs-path> --test-libs=lib-core.input-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/input/README.md - Spec:
meta/docs/superpowers/specs/2026-05-12-p3-3-mouse-input-design.md