Repository navigation
test(coverage-gap): pin DiskSpaceMonitorCoordinator — the class that decides whether a full disk stops your session (13 cases, 12/12 mutants killed) - #398
Conversation
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
/agentic_review |
PR Summary by QodoAdd characterization coverage for disk-space coordination
AI Description
Diagram
High-Level Assessment
Files changed (1)
|
Code Review by Qodo🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)
Great, no issues found!Qodo reviewed your code and found no material issues that require reviewTip of the day💡 Did you know, you can type 'qodo, fix this' on a finding and the fix lands right on your PR |
|
/agentic_review |
|
Code review by qodo was updated up to the latest commit 8e2bb7e |
|
Qodo-clean, CI green — ready for review. Head |
|
/agentic_review |
|
Code review by qodo was updated up to the latest commit 8e2bb7e |
|
Qodo-clean, CI green — ready for review. Head |
The PR remains clean at |
|
Sweep (13-way merge build): all 13 PRs are clean together on Covered: #387 Per PR: every head matches its ready note. Every PR is
Merge build: I merged
Test count reconciles exactly: 993 on Cross-PR hazards checked:
No merge was performed and nothing was pushed to any PR branch. |
Not merging — for review. Routine:
coverage-gap. Tests only, no production change.What was untested
DiskSpaceMonitorCoordinatordecides what a low disk does: whether the logging toggle may turn on, which dialog the user sees, and whether a running session gets stopped before SQLite fills the volume mid-write.DiskSpaceMonitorTestsalready pins the monitor's thresholds (50/100/500 MB). Nothing pinned the coordinator. It was referenced once in the test project, in a doc comment.How I checked it was untested: a case-insensitive search of
Daqifi.Avalonia.Tests/for the class name and for each member and seam:EvaluateStartLogging,DiskSpaceStartDecision,OnCriticalSpaceReached,IDiskSpaceMonitorHost,ShowDiskSpaceMessage. The only hit was that comment (DeviceRefusalCrashTests.cs:93). Positive control: the same search does find the event namesLowSpaceWarning/CriticalSpaceReachedinDiskSpaceMonitorTests.cs, which really is tested.What this adds
One file,
Daqifi.Avalonia.Tests/DiskSpace/DiskSpaceMonitorCoordinatorTests.cs, +313/−0. That's 13 test cases (9 methods; two are theories). They use hand-rolled monitor and host doubles, with no timer and no dispatcher. Net-additive because it is a coverage PR. It adds no production code, no abstraction and no helper shared outside the file.Plain characterisation (these pass on
mainby design)Ok→Allowedwith no dialog.PreSessionWarning→AllowedWithWarning.Warning→AllowedWithWarning.Critical→Blocked. Each case also asserts the dialog title.StartMonitoringpasses the suppress flag straight through, andStopMonitoringis forwarded.Tests that pin something subtle
Warningis in the gate table on purpose. The pre-session check returnsWarning(notPreSessionWarning) for 50–100 MB, so if that leg were dropped, a nearly full disk would start logging with no warning at all.StopLogging. Nothing is running yet, and the host'sStopLoggingwritesIsLogging = falsefrom inside the very setter that is asking.Cannot Start Loggingmessage only. The other three messages are exercised with whole-MB values, so a rounding change confined to one of them would not be caught.)StopLoggingthrows, the exception escapes and no dialog is shown. This is current behaviour, pinned but not endorsed — the test's doc comment says so and that a change should have to update the test on purpose. It is not a live defect:DiskSpaceMonitor.OnTimerTickcatches and logs the exception, and the production host (DaqifiViewModel'sIDiskSpaceMonitorHost.StopLogging) setsIsLogging = falsedirectly on the UI thread and otherwise posts to the dispatcher; the monitor's tick arrives on a timer thread, so it posts. So it's pinned, not filed.Disposeunsubscribes from both events and disposes the monitor exactly once, even when called twice. A tick already in flight cannot then stop a session or open a dialog on a view model that has been torn down.Verification
Mutation testing, 12 mutants, all killed. Each was made on
DiskSpaceMonitorCoordinator.cs, then the file was restored from git andtouched.Blocked→Allowedon the critical branchCritical)|| Level == WarningWarning)StopLoggingDisposekeeps the critical subscriptionDisposenever latches_disposedStopLoggingStartMonitoring(true)constantfalse)StopMonitoringbecomes a no-opDisposekeeps the low-space subscriptionMutants 7–9 and 11–12 ran in two combined builds. Each mutant in a combined build was in a different method, and each went red in exactly the test that claims it.
Shepherd re-run (independent, single fresh edit per mutant,
touchafter restore, each build confirmed to recompileDaqifi.Avalonia.Tests.dlland run all 13 cases): mutants 2, 3, 9 and 12 re-made and re-measured. feat(sd): enable SD-card offload over WiFi/TCP (closes #1) #2 → 12/13, theWarningtheory row failed. reliability: device layer never notifies IsConnected transitions (stale command/UI state on silent drops) #3 → 11/13, both critical-event tests failed. fix(mobile): nav tab labels & count diverge from desktop (Stream≠Live Graph, Storage≠Logged Data, 4 vs 5) #9 (Math.Roundon the gate's critical message) → 12/13, the truncation test failed. polish(desktop): assorted flyout/pane parity nits (settings highlight, scrollbar, wrap width, glyphs, gridlines) #12 → 12/13, the Dispose test failed. Unmutated baseline and post-restore run: 13/13. No sleeps, wall-clock waits or timer dependence anywhere in the file; the never-completing dialogTaskmakes any path that awaited a dialog hang rather than pass.Gate (under a
build.2lock): desktop build, iOS restore, and iOS Releaseiossimulator-arm64 --no-restoreall exited 0.dotnet teston the full suite: 1006 passed, 0 failed, 0 skipped.Warnings: the diff only touches the test project, and neither head compiles it. The
dotnet testbuild shows 0 warnings from the new file. That comes from a forced--no-incrementalrebuild of the test project: it printed 338 warning lines, none fromDaqifi.Avalonia.Tests/.No lock-file changes. No device involvement, so no bench run.
Base and collisions: the PR's base is
642caef, which is currentmain, so CI's run on8e2bb7eis a build of main + this PR. None of the other open PRs (test(#327): one dialog-DataContext guard — the shared helper follows new+DataContext, DuplicateDeviceDialog's 412-line copy goes (−369) #387, fix(#327): LoggedSessionsMobileView's 51 bindings were all on reflection — one declared scope, two inferred, three $parent hops #389–fix(#327): LoggedDataPanePrototype's 102 bindings were all on reflection — root scope, two declared template scopes, two existing item scopes #396, chore(deps): Bump the minor-and-patch group with 17 updates #363) adds or touches aDiskSpacefile or any interface these doubles implement.Test-double note:
RecordingLoggeris the tenth privateIAppLoggerdouble in the test project; there is no shared one to reuse, so this follows the existing convention rather than duplicating a helper.🤖 Generated with Claude Code