test(coverage): raise unit coverage past the 50% gate (phases 0-2) #27

Merged
whitlocktech merged 1 commits from test/coverage-phase-0-1-2 into main 2026-07-22 21:11:57 +00:00
Member

What & why

After the JaCoCo wiring landed (#26), SonarQube measured new-code coverage at 16.4% — below the 50% quality gate. This executes phases 0–2 of docs/android/COVERAGE_PLAN.md to clear it. Estimated new-code coverage after this change: ~57% (measured from the local JaCoCo report with the Sonar coverage-exclusions applied by source file).

109 new tests across 19 files; the full suite is now 264 tests, all green.

Phase 0 — coverage exclusions (sonar-project.properties)

Drop code a JVM unit test physically can't execute from the coverage denominator (it stays analysed for bugs/smells): pure-@Composable UI the *Screen.kt glob missed (ui/components/**, BlockRenderer, ShardComponents), and Android-framework glue (push foreground services, Keystore-backed Encrypted* stores, Hilt di/**).

Phase 1 — DTO serialization tests

Decode + encode + computed-helper coverage for the previously-untested/partial DTOs: AdminDto, PublicDto, WikiDto, post/page/contact, SsoDto, the shard board DTOs and player game-data DTOs, and the mobile-auth request bodies — including isPublished / isMaintenance / ActorDto.label / ShardStatusDto.isOnline, plus the ApiResult.map / isShardUnavailable helpers.

Phase 2 — ViewModel tests (the main lever)

A MainDispatcherRule harness + hand-written API fakes (FakePublicApi / FakeAdminApi / FakePlayerShardApi / FakeShardStream, no new deps — matches the repo's no-mock convention) drive real repositories into the ViewModels, so repository code is exercised too. Covers:

  • Admin — dashboard, content, moderation, support (load success/error, form validation, 403/404/503 role- & status-aware feedback)
  • Content — news, post, page, wiki, wiki-page, home, contact (+ SavedStateHandle args, validation, mailer-fallback)
  • Player — characters, vendors, character, my-houses (link/create-account validation + error mapping)
  • Shard boards — champs, guilds, governors, houses, hub (snapshot load and live-frame merge/remove via a scripted fake stream)

One small production change (no behaviour change)

To make the shard boards unit-testable, a small ShardStream interface is extracted from ShardStreamClient (bound in NetworkModule) so ShardRepository depends on the capability, not the OkHttp client — a fake stream then replaces the perpetual SSE reconnect loop in tests. Verified with assembleDebug (Hilt graph intact).

Deferred (noted as later additions)

Phases 3 (repositories) and 4 (core net/auth top-up) are follow-ups, and the deep-dependency auth family (LoginViewModel, AccountViewModel, TrustedDevicesViewModel, AuthRepository, which pull in SessionManager / SsoAuthManager / encrypted stores) lands with them.

Verification

./gradlew testDebugUnitTest jacocoTestReport assembleDebugBUILD SUCCESSFUL, 264 tests pass. The gate result is confirmed by the post-merge Sonar scan.


[x] AI-assisted: authored with Claude Code (Claude Opus 4.8). AI-authored commits carry a Co-Authored-By trailer.

🤖 Generated with Claude Code

## What & why After the JaCoCo wiring landed (#26), SonarQube measured **new-code coverage at 16.4%** — below the **50%** quality gate. This executes phases 0–2 of [`docs/android/COVERAGE_PLAN.md`](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/android/COVERAGE_PLAN.md) to clear it. **Estimated new-code coverage after this change: ~57%** (measured from the local JaCoCo report with the Sonar coverage-exclusions applied by source file). **109 new tests across 19 files; the full suite is now 264 tests, all green.** ## Phase 0 — coverage exclusions (`sonar-project.properties`) Drop code a JVM unit test physically can't execute from the *coverage* denominator (it stays **analysed** for bugs/smells): pure-`@Composable` UI the `*Screen.kt` glob missed (`ui/components/**`, `BlockRenderer`, `ShardComponents`), and Android-framework glue (push foreground services, Keystore-backed `Encrypted*` stores, Hilt `di/**`). ## Phase 1 — DTO serialization tests Decode + encode + computed-helper coverage for the previously-untested/partial DTOs: `AdminDto`, `PublicDto`, `WikiDto`, post/page/contact, `SsoDto`, the shard board DTOs and player game-data DTOs, and the mobile-auth request bodies — including `isPublished` / `isMaintenance` / `ActorDto.label` / `ShardStatusDto.isOnline`, plus the `ApiResult.map` / `isShardUnavailable` helpers. ## Phase 2 — ViewModel tests (the main lever) A `MainDispatcherRule` harness + hand-written API fakes (`FakePublicApi` / `FakeAdminApi` / `FakePlayerShardApi` / `FakeShardStream`, no new deps — matches the repo's no-mock convention) drive **real repositories** into the ViewModels, so repository code is exercised too. Covers: - **Admin** — dashboard, content, moderation, support (load success/error, form validation, 403/404/503 role- & status-aware feedback) - **Content** — news, post, page, wiki, wiki-page, home, contact (+ SavedStateHandle args, validation, mailer-fallback) - **Player** — characters, vendors, character, my-houses (link/create-account validation + error mapping) - **Shard boards** — champs, guilds, governors, houses, hub (snapshot load **and** live-frame merge/remove via a scripted fake stream) ### One small production change (no behaviour change) To make the shard boards unit-testable, a small `ShardStream` interface is extracted from `ShardStreamClient` (bound in `NetworkModule`) so `ShardRepository` depends on the capability, not the OkHttp client — a fake stream then replaces the perpetual SSE reconnect loop in tests. Verified with `assembleDebug` (Hilt graph intact). ## Deferred (noted as later additions) Phases **3** (repositories) and **4** (core net/auth top-up) are follow-ups, and the deep-dependency **auth family** (`LoginViewModel`, `AccountViewModel`, `TrustedDevicesViewModel`, `AuthRepository`, which pull in `SessionManager` / `SsoAuthManager` / encrypted stores) lands with them. ## Verification `./gradlew testDebugUnitTest jacocoTestReport assembleDebug` → **BUILD SUCCESSFUL**, 264 tests pass. The gate result is confirmed by the post-merge Sonar scan. --- > [x] **AI-assisted:** authored with Claude Code (Claude Opus 4.8). AI-authored commits carry a `Co-Authored-By` trailer. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
wtclaude added 1 commit 2026-07-22 21:04:31 +00:00
test(coverage): raise unit coverage past the 50% gate (phases 0-2)
All checks were successful
PR Checks / android-build (pull_request) Successful in 7m19s
4e3bb914ff
Executes COVERAGE_PLAN.md phases 0-2 to clear the SonarQube new-code coverage
gate (was 16.4%, threshold 50%). Estimated new-code coverage after this change
is ~57%. 109 new tests across 19 files; full suite is 264 tests, all green.

Phase 0 — coverage exclusions (sonar-project.properties): drop code a JVM unit
test can't execute from the *coverage* denominator (still analysed for
bugs/smells) — pure-@Composable UI the `*Screen.kt` glob missed
(ui/components/**, BlockRenderer, ShardComponents), Android-framework glue
(push services, Keystore-backed Encrypted* stores, Hilt di/**).

Phase 1 — DTO serialization tests: AdminDto, PublicDto, WikiDto, PostDto/PageDto/
ContactDto, SsoDto, the shard board DTOs and player game-data DTOs, and the
mobile-auth request bodies — decode + encode + computed helpers
(isPublished/isMaintenance/ActorDto.label/ShardStatusDto.isOnline).

Phase 2 — ViewModel tests: a MainDispatcherRule harness + hand-written API fakes
(FakePublicApi/FakeAdminApi/FakePlayerShardApi/FakeShardStream) drive real
repositories into the ViewModels. Covers the admin (dashboard/content/moderation/
support), content (news/post/page/wiki/home/contact), player (characters/
vendors/character/my-houses) and shard-board (champs/guilds/governors/houses/
hub) ViewModels — load success/error, form validation, role/status-aware
feedback, and live-frame merging.

To make the shard boards testable, extract a small `ShardStream` interface from
`ShardStreamClient` (bound in NetworkModule) so `ShardRepository` depends on the
capability, not the OkHttp client — lets a fake stream replace the perpetual SSE
reconnect loop in tests. No production behaviour change.

Phases 3 (repositories) and 4 (core net/auth top-up) are follow-ups; the
deep-dependency auth family (Login/Account/TrustedDevices ViewModels,
AuthRepository) lands with them. See docs/android/COVERAGE_PLAN.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NgyHnrNa8WwG3doxvxjuCr
whitlocktech approved these changes 2026-07-22 21:07:00 +00:00
whitlocktech scheduled this pull request to auto merge when all checks succeed 2026-07-22 21:07:04 +00:00
whitlocktech merged commit 7fc497a1a4 into main 2026-07-22 21:11:57 +00:00
whitlocktech deleted branch test/coverage-phase-0-1-2 2026-07-22 21:11:57 +00:00
Sign in to join this conversation.
No description provided.