test(coverage): close clean JVM-testable coverage gaps #291

Merged
JMR-dev merged 2 commits from test-288-coverage-gaps into main 2026-07-04 06:21:57 +00:00
JMR-dev commented 2026-07-04 06:04:57 +00:00 (Migrated from github.com)

Closes #288

Closes the cleanly JVM-testable coverage gaps from the Phase-2 JaCoCo audit. All changes are test-only (7 existing suites extended, 2 net-new); no production code touched. Each targeted class reached 100% line coverage (source-file aggregate), comfortably clearing the ~95% bar.

Class Before After
data/settings/AccountSettingsRepository 38.5% 100%
data/settings/SignatureRepository 63.2% 100%
data/security/CredentialStore (new) 0% 100%
data/security/EncryptedCacheGuard (new) 0% 100%
data/attachment/AttachmentUriGrants 5.3% 100%
data/sync/SyncScheduler 90.2% 100%
ui/lock/AppLockViewModel 92.8% 100%
mail/SmtpSender 91.8% 100%
ui/reporting/StartupReportViewModel 93.3% 100%

What each test adds

  • AccountSettingsRepository — observe Flow (Turbine) + the sibling setters (setSignatureEnabled/setNotificationsEnabled/setRetentionCount/setRetentionMonths, including the negative-clamp and null-inherit cases).
  • SignatureRepository — observeForAccount/get/getDefault/update (+ the no-op-for-unknown-id branch) and the toDomain mapping.
  • CredentialStore (new) — encrypt-on-save / decrypt-on-load / null-on-missing / delete, with KeystoreCrypto mocked as identity (the AES-GCM round-trip is device-bound).
  • EncryptedCacheGuard (new) — the full isCacheLocked() truth table over appLock/encryptCache/isUnlocked.
  • AttachmentUriGrants — releaseUnreferenced/referencedUris wiring: empty-set short-circuit, still-referenced guard (drafts + outbox), and the swallowed SecurityException when releasing a grant never held.
  • SyncScheduler — schedulePeriodicReportPurge (UPDATE policy + unique name).
  • AppLockViewModel — distinct lock nonce, the onBackground cover branch, the unwrapSealedPassphrase cancellation rethrow, and the awaitSyncEnqueue execution-failure and interrupt branches.
  • SmtpSender — the send error paths (required-STARTTLS-unavailable and implicit-TLS-fails) plus the cc-recipient and inline-image-with-a-regular-attachment (bodyPart related-in-mixed) body branches.
  • StartupReportViewModel — the @Inject real-clock constructor.

Validation (no emulator — pure JVM)

:app:testDebugUnitTest + :app:jacocoTestReport + :app:ktlintCheck + :app:detekt all green.

🤖 Generated with Claude Code

Closes #288 Closes the cleanly JVM-testable coverage gaps from the Phase-2 JaCoCo audit. All changes are **test-only** (7 existing suites extended, 2 net-new); no production code touched. Each targeted class reached **100% line coverage** (source-file aggregate), comfortably clearing the ~95% bar. | Class | Before | After | |-------|:------:|:-----:| | `data/settings/AccountSettingsRepository` | 38.5% | **100%** | | `data/settings/SignatureRepository` | 63.2% | **100%** | | `data/security/CredentialStore` (new) | 0% | **100%** | | `data/security/EncryptedCacheGuard` (new) | 0% | **100%** | | `data/attachment/AttachmentUriGrants` | 5.3% | **100%** | | `data/sync/SyncScheduler` | 90.2% | **100%** | | `ui/lock/AppLockViewModel` | 92.8% | **100%** | | `mail/SmtpSender` | 91.8% | **100%** | | `ui/reporting/StartupReportViewModel` | 93.3% | **100%** | ### What each test adds - **AccountSettingsRepository** — `observe` Flow (Turbine) + the sibling setters (`setSignatureEnabled`/`setNotificationsEnabled`/`setRetentionCount`/`setRetentionMonths`, including the negative-clamp and null-inherit cases). - **SignatureRepository** — `observeForAccount`/`get`/`getDefault`/`update` (+ the no-op-for-unknown-id branch) and the `toDomain` mapping. - **CredentialStore** (new) — encrypt-on-save / decrypt-on-load / null-on-missing / delete, with `KeystoreCrypto` mocked as identity (the AES-GCM round-trip is device-bound). - **EncryptedCacheGuard** (new) — the full `isCacheLocked()` truth table over `appLock`/`encryptCache`/`isUnlocked`. - **AttachmentUriGrants** — `releaseUnreferenced`/`referencedUris` wiring: empty-set short-circuit, still-referenced guard (drafts + outbox), and the swallowed `SecurityException` when releasing a grant never held. - **SyncScheduler** — `schedulePeriodicReportPurge` (UPDATE policy + unique name). - **AppLockViewModel** — distinct lock nonce, the `onBackground` cover branch, the `unwrapSealedPassphrase` cancellation rethrow, and the `awaitSyncEnqueue` execution-failure and interrupt branches. - **SmtpSender** — the `send` error paths (required-STARTTLS-unavailable and implicit-TLS-fails) plus the cc-recipient and inline-image-with-a-regular-attachment (`bodyPart` related-in-mixed) body branches. - **StartupReportViewModel** — the `@Inject` real-clock constructor. ### Validation (no emulator — pure JVM) `:app:testDebugUnitTest` + `:app:jacocoTestReport` + `:app:ktlintCheck` + `:app:detekt` all green. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.