Skip to content

[R2-9][P3] Add game-ui test coverage (108 pub fns, 0 tests — grade F) #845

Description

@MichaelFisher1997

Part of #839 — [Audit][Round 2] A++ umbrella.
Phase: P3 · Finding: R2-9 · Priority: HIGH (grade F module)

Problem

game-ui has 108 pub fns, 0 tests. All UI screens, menus, and widgets are untested. This is one of two grade-F modules in the codebase (the other is engine-rhi, addressed in R2-4). UI bugs (broken navigation, dead buttons, layout regressions on resize) ship silently.

Evidence

  • find modules/game-ui -name '*.zig' | xargs grep -l '^test ' → zero results
  • modules/game-ui/src/screens/world.zig is 969 LOC; screens/home.zig, screens/world_list.zig, screens/graphics.zig, screens/settings.zig are all untested
  • 108 pub fns across the module (screen lifecycle, input handling, widget state machines, settings binding)
  • Co-located tests are an explicit AGENTS.md rule: "Add tests alongside modules"

For contrast:

  • engine-math ratio 4.00 (A)
  • world-core ratio 2.33 (A)
  • world-meshing ratio 2.09 (A)
  • game-ui ratio 0.00 (F)

Fix

Three layers, in order of return-on-investment:

Layer 1 — Pure state machines (highest ROI, no GPU)

Extract and test the pure-logic cores of each screen:

  • WorldListScreen state: filter/sort logic, world-metadata parsing, selection state → world_list_state.zig. Test sorting, filtering, pagination.
  • SettingsScreen state: keybind rebinding, graphics-preset application, value clamping → settings_state.zig. Test value clamping, keybind conflict detection.
  • GraphicsMenu state: preset matrix, slider-to-setting mapping → graphics_menu_state.zig. Test preset application, slider clamping.

Target: 60+ tests across these state modules. Lifts game-ui ratio from 0.00 to ~0.5.

Layer 2 — Mock UI host

Build on engine-ui's existing test harness (if any). Create modules/game-ui/src/test_host.zig:

  • MockInputHost — implements IInputHost (fake keyboard/mouse events)
  • MockDrawHost — implements IDrawHost (records draw calls instead of executing them)
  • MockNavigationHost — implements INavigationHost (records push/pop transitions)

Then screens/*_tests.zig can exercise lifecycle: init → input("Enter") → update() → assert navigated to next screen.

Layer 3 — Visual regression hooks

Where headless graphics rendering is feasible (R2-4 mock RHI), wire 2-3 happy-path screen tests through the existing headless-screenshot skill to catch layout regressions.

Verification

  • nix develop --command zig build test -- --test-filter "WorldListState" and similar
  • nix develop --command zig build test overall still green
  • Coverage target: game-ui ratio ≥ 0.4 (43+ tests for 108 pub fns). Stretch: ≥ 0.7 (grade B+).
  • Co-locate tests under modules/game-ui/src/screens/*_tests.zig per AGENTS.md.
  • Wire into the test aggregator at src/tests.zig.

Constraints

  • Tests must run without a GPU (Layer 1 + 2) or with mock RHI (Layer 3).
  • No production code changes unless extraction is required to make it testable (Layer 1). Extracted state modules are a legitimate refactor.
  • One PR per layer is acceptable.
  • Conventional commits: test(game-ui): add WorldListScreen state tests, test(game-ui): add mock UI host for screen lifecycle, etc.

Notes

  • Coordinate with R2-8 (silent-error surfacing) — the toast-mock harness developed here benefits both.
  • Layer 1 extraction (state-machine pull-out) is also good SRP discipline — fat screens like world_list.zig and world.zig (969 LOC) benefit from having their pure cores separated from rendering.
  • Future: a game-ui-test-coverage CI gate (codecov threshold) would prevent regression. Out of scope here; tracked in Production-Readiness Audit: missing CI / lint / benchmark / regression guardrails #834.

Tracking: #839

Metadata

Metadata

Assignees

No one assigned

    Labels

    automated-auditIssues found by automated opencode audit scansbugSomething isn't workingenhancementNew feature or requestgamehotfix

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions