Skip to content

Coverage round 2 batch C: AppState-constructible tests, dialog states, project load/export - #110

Merged
sdercolin merged 5 commits into
devfrom
tests/coverage-batch-5
Jul 10, 2026
Merged

sdercolin merged 5 commits into
devfrom
tests/coverage-batch-5

Conversation

@sdercolin

Copy link
Copy Markdown
Owner

Summary

Final batch of coverage round 2 (items 4, 5, 7 and the AppState refactor of 8): 83 new tests (1092 total), line coverage 58.9% → 61.5%, koverVerify bound raised 56 → 59.

Production refactor (behavior-preserving)

IpcState is now an interface with IpcStateImpl as the real implementation, injected into AppState via a factory parameter (default { IpcStateImpl(it) }). This lets tests construct a real AppState with a FakeIpcState — no port binding, no reflection. Production behavior is unchanged (default factory starts the real server). New shared helpers: testutil.TestAppState.create(scope) and testutil.FakeIpcState.

AppState glue + dialog state (44 tests)

Screen switching and project open/close wiring, plugin/labeler disabled-name filtering, error pending actions, exit() closing ipcState (verified via FakeIpcState); AppDialogState standalone/embedded open-close-stacking, the awaitEmbeddedDialog request/result flow, closeAllDialogs, dialog queries.

Remaining dialog states (36 tests)

Project settings (validation, submit/cancel), sample list (missing- and excluded-sample handling, redirect), import-entries module mapping, updater version comparison (no network).

io/Project (18 tests)

awaitLoadProject labeler-version reconciliation — existing labeler newer/older/unknown, auto-install vs RequiredLabelerNotFoundException, parse error, missing file, cache-dir/path redirect, auto-saved path; exportProject/exportProjectModule raw-label writes; openCreatedProject, importProjectFile.

Suspected bugs found (pinned, NOT fixed)

  1. closeAllDialogs is incomplete — it clears only a subset; About/License/Import/Updater/ImportEntries/ReloadLabel/QuickEdit/Prerender/etc. survive a screen switch or opening another dialog (changeScreen calls closeAllDialogs).
  2. anyDialogOpeningExceptMacroPluginManager() doesn't exclude the macro-plugin manager — returns true whenever the customizable-item manager is shown, so isMacroPluginAvailable is false while that dialog is open.
  3. importProjectFile swallows parse errors — importModulesFromProject catches everything and returns an empty list, so a malformed project opens the import dialog with zero modules instead of surfacing ProjectImportException.
  4. File.getDirectory() redirects to parent on a non-existent leaf name, so sample-dir / download-position redirect handlers silently target the parent.
  5. Minor: ProjectSettingDialogState.isOutputFileValid false for empty string vs createNewProject treating empty as null.

Note: isDebug evaluates true under the Gradle test worker — relevant to any prerelease-filtering or unknown-key-parsing tests.

Test plan

  • ./gradlew jvmTest — 1092 tests, 0 failures
  • ./gradlew koverVerify ktlintCheck
  • ipc-package tests still green after the interface extraction

🤖 Generated with Claude Code

…2 batch C)

Coverage round 2 batch C (83 new tests, 1092 total; line coverage 59% -> 62%):

Production refactor (behavior-preserving):
- Extract an IpcState interface with IpcStateImpl as the real implementation,
  injected into AppState via a factory (default builds the real server). This
  lets tests build a real AppState with a FakeIpcState instead of binding the
  IPC port, dropping the need for reflection-based AppState construction.

Tests (via the new testutil.TestAppState / testutil.FakeIpcState helpers):
- AppState glue: screen switching, project open/close wiring, plugin/labeler
  disabled-name filtering, error pending actions, exit() closing ipcState
- AppDialogState: standalone/embedded dialog open/close/stacking, the
  awaitEmbeddedDialog request/result flow, closeAllDialogs, dialog queries
- Remaining dialog states: project settings, sample list (missing/excluded
  samples), import-entries module mapping, updater version comparison
- io/Project: awaitLoadProject labeler-version reconciliation branches
  (newer/older/unknown labeler, install/RequiredLabelerNotFound), export
  paths, openCreatedProject, importProjectFile

koverVerify bound raised from 56 to 59 (new baseline 62%).

Several suspected bugs found and pinned (not fixed), see the PR description.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread src/jvmMain/kotlin/com/sdercolin/vlabeler/ui/AppState.kt
sdercolin and others added 4 commits July 10, 2026 16:39
It returned true whenever the customizable item manager was shown, including
for the MacroPlugin type, so it did not actually exclude the macro-plugin
manager (and isMacroPluginAvailable was false while that dialog was open).
Now it excludes the MacroPlugin manager type; anyDialogOpening() still counts
it via its explicit MacroPlugin clause.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
It previously cleared only a subset, so the About, License, Import, Prerender,
EntrySampleSync, TrackingSettings, FileNameNormalizer, QuickEdit, Updater,
ImportEntries and ReloadLabel dialogs stayed open across a screen switch or
when another dialog was opened (both of which call closeAllDialogs). It now
resets all dialog state.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
importModulesFromProject swallowed all failures and returned an empty list,
so importProjectFile silently opened the import dialog with zero modules for
a malformed project file instead of showing an error. It now lets structural
failures (malformed JSON, missing labelerConf) propagate, while a valid
project with no importable entries still returns an empty list. importProjectFile
already wraps the call and surfaces the error via ProjectImportException.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
isOutputFileValid returned false for an empty-string output file (File("").parentFile
is null), so a dialog whose output file initializes to empty (an editable
module with no raw file) opened in an error state that blocked submit, even
though empty means "no output file" and createNewProject already handles it
via ifEmpty { null }. Empty is now treated as none, consistent with null.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sdercolin
sdercolin merged commit 238db99 into dev Jul 10, 2026
1 check passed
@sdercolin
sdercolin deleted the tests/coverage-batch-5 branch July 10, 2026 09:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant