Close the biggest test gaps: composed resource keys, commands, tool discovery - #4
Merged
Merged
Conversation
This was referenced Aug 12, 2026
Kentarohakase
force-pushed
the
hardening/cancellation-and-ui-responsiveness
branch
from
August 12, 2026 00:56
fa1684e to
56e3df3
Compare
Kentarohakase
force-pushed
the
tests/close-coverage-gaps
branch
from
August 12, 2026 00:56
e894726 to
e6c1686
Compare
Kentarohakase
force-pushed
the
hardening/cancellation-and-ui-responsiveness
branch
from
August 12, 2026 01:01
56e3df3 to
b7f755d
Compare
Several texts are looked up under a key composed from an enum value, so adding an enum member shipped a missing-resource marker to the user with no compiler error and no test to stop it. The existing resource test walked a hand written list of about sixty values and could not catch that. A new test enumerates every member of every enum used that way and resolves the keys it produces, in both languages. Verified by adding a member without a resource entry: the test names exactly the two keys that are missing. The command types had no tests at all although they carry the guard that keeps a failing command from ending the session. Reentry, the error handler, the cancellation path and the typed parameter handling are covered now, as is Result, whose failure case may legitimately still carry a value. Tool discovery had no tests either. Path resolution, the fallback to the bare name, the caching of a successful probe and the new caching of a failed one are covered. The update check gets its first tests through the constructor that takes an HttpClient specifically for that purpose and was unused until now; it also propagates a cancellation instead of reporting it as no update available. Test classes no longer run in parallel: several change the process wide localization culture while others assert on localized text.
Kentarohakase
changed the base branch from
hardening/cancellation-and-ui-responsiveness
to
main
August 12, 2026 01:03
Kentarohakase
force-pushed
the
tests/close-coverage-gaps
branch
from
August 12, 2026 01:03
e6c1686 to
90d55cd
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #3. Phase 3 of the improvement plan: 239 tests, up from 204.
The gap that could ship a bug to users
Several texts are looked up under a key composed from an enum value —
ValidationFinding_{kind}_Title,AnalysisFinding_{kind}_Message,BatchStatus_{status}, and six more families. Adding a member toAudioComparisonFindingKindorBatchProcessingStatusproduced no compiler error and no test failure; it simply shipped a missing-resource marker into the interface.ResourceTests.VisibleModelTexts_DoNotContainMissingResourceMarkerswalked a hand-maintained list of about sixty values, so it could not cover this.ComposedResourceKeys_ResolveForEveryEnumValuenow enumerates every member of every enum used that way and resolves the keys it produces, in both languages.I verified it actually bites rather than trivially passing: adding a member without a resource entry turned it red and named exactly the two missing keys.
The probe member was removed again.
New coverage
CommandTests—AsyncRelayCommand,RelayCommandandRelayCommand<T>had no tests at all, althoughAsyncRelayCommandcarries the guard that keeps a failing command from ending the session (Keep failing commands, slow tools and untrusted update links from breaking the session #2). Covered: reentry is blocked while a run is in flight, the error handler receives the failure, a cancellation is a normal outcome, the command becomes executable again afterwards, and the typed parameter handling including a mismatched type.ResultTests— including the case every consumer has to remember: a failure may still carry a value, which is how a critical validation report reaches the UI.ToolDiscoveryServiceTests— 245 lines that had no tests. Covered: path resolution, the fallback to the bare executable name, the caching of a successful probe, and the caching of a failed one from Make long running steps cancellable and keep the queue from stalling the UI #3. The probe useswhere.exe /?— always present on Windows and the same shape as<tool> -version, without needing FFmpeg on the runner. (cmd.exe /?is unusable: it prints help but exits 1.)AppUpdateServiceTests—CheckAsynchad no tests despiteAppUpdateServicehaving aninternalconstructor that takes anHttpClientspecifically to make it testable. AFakeHttpMessageHandlercovers a newer release, an up-to-date version, an untrusted link falling back to the releases page, a 404, a malformed payload, a missing tag, an unreachable host, and cancellation.One production change
AppUpdateService.CheckAsynccaughtOperationCanceledExceptionalong with everything else, so a caller that cancelled was told there was no update. It now rethrows when the caller's own token was cancelled; its internal timeout still surfaces as "no update".Latent flakiness removed
LocalizationService.Instance.Cultureis process-wide state and its setter also writesCultureInfo.DefaultThreadCurrentUICulture. Six test methods across four classes mutate it while other classes assert on localized text, and xUnit runs test classes in parallel by default. The suite takes nine seconds, so serializing it via[assembly: CollectionBehavior(DisableTestParallelization = true)]is the cheap and complete fix.Verification
Still not covered
MainViewModel— about 2,100 lines across eleven partials — remains untested. Its constructor instantiates eighteen services itself and is the de-facto composition root, so there is no seam to construct it in a test. That needs a constructor refactor, which is its own change rather than a by-product of this one.