Commit graph

2 commits

Author SHA1 Message Date
6505a3cab0 test: services — NotesService, UpdateChecker, PresetApplier, OscBridge, IsoController
Punch-list items 19–25 — covers six of the seven services + the
engine controller. TeamsLauncher fallback chain (item 21) is deferred:
it depends on Process.Start in ways that don't unit-test cleanly
without a process-launch seam that the May 2026 codebase doesn't
have yet.

Service seams added for testability (each marked internal + a
matching InternalsVisibleTo-equivalent grant via the existing
TeamsISO.App.Tests visibility):
* NotesService.DirectoryOverride — redirect %LOCALAPPDATA%\TeamsISO\Notes
* WindowStateStore.PathOverride — redirect window.json
* UpdateChecker.StateDirectoryOverride — redirect both the 24h
  cooldown stamp and the no-update-check.flag
* UpdateChecker.TryParseSemVer — visibility bumped to internal
* OscBridge.DispatchAsync — visibility bumped to internal so tests
  can drive route dispatch without spinning up the UDP receive loop

New test files (App.Tests):
* Services/NotesServiceTests.cs (6 cases) — header-once, timestamp
  format, multi-append, whitespace trim + reject, today-path shape.
* Services/UpdateCheckerTests.cs (7 cases) — TryParseSemVer Theory
  across the v?X.Y.Z(.N)(-suffix) inputs the real release stream
  produces, semver ordering pin, CheckIfDueAsync short-circuit on
  recent stamps (the throttle never fires HTTP — deterministic
  offline), LaunchCheckEnabled round-trip via the opt-out flag.
* Services/PresetApplierTests.cs (6 cases) — the four enable/disable
  state transitions, case-insensitive display-name join, partial
  meeting (preset names participants not present), live participants
  unnamed by the preset stay untouched.
* Services/PresetStoreCollection.cs — xUnit collection so any test
  class that mutates OperatorPresetStore.PathOverride serializes
  with siblings that do the same. OperatorPresetStoreTests now joins
  the collection (the class comment claimed it didn't need one
  because file paths were per-test-unique — true, but PathOverride
  is shared static state, which is why the new PresetApplierTests
  was clobbering its result on first run).
* Services/WindowStateStoreTests.cs (6 cases) — JSON round-trip
  through the Snapshot record + all the bail paths (no file, too
  small, too large, fully off-screen, garbage JSON). Full Window
  property write coverage is deferred to branch 11 (needs STA).
* Services/OscBridgeDispatchTests.cs (5 cases) — /teamsiso/refresh-
  discovery + unknown-address + /teamsiso/notes + clean bail when
  the toggle/preset paths can't reach a dispatcher.

New test cases (Engine.Tests):
* Controller/IsoControllerTests.cs gains three cases —
  SetRecording_TogglesEnabledAndStoresDirectory,
  AddRecordingMarker_NoOpsCleanly_WhenNoActiveRecorders,
  RefreshDiscovery_SetsRefreshFlagOnDiscoveryService.

Tests: 56 → 128 in App.Tests; 103 → 106 in Engine.Tests. Total
green: 234. Build clean (0 warnings, 0 errors).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 21:06:45 -04:00
0c82ac71f0 feat: bundle Inter font, emergency stop button, window persistence + tests
Some checks failed
CI / build-and-test (push) Failing after 27s
Four polish items + a test pass.

1. Inter Variable (rsms/inter v3.19, OFL) is bundled at Assets/Fonts/Inter.ttf (~800 KB) and registered as a WPF Resource. WildDragonTheme.xaml's Wd.Font.Sans now points at pack://application:,,,/Assets/Fonts/#Inter so the typography matches wilddragon.net regardless of whether the user has Inter installed system-wide. Falls back to Segoe UI Variable Display if the resource is missing.

2. 'Stop all ISOs' button at the right of the participants header. Bound to a new MainViewModel.StopAllIsosCommand that snapshots the enabled list, awaits DisableIsoAsync sequentially, and silently swallows per-pipeline failures (best-effort emergency stop). CanExecute gates on whether any ISO is currently enabled.

3. WindowStateStore service persists the main window's Left/Top/Width/Height/State to %LOCALAPPDATA%\\TeamsISO\\window.json on close and restores it on SourceInitialized. Multi-monitor friendly: a saved position with no corner inside any virtual screen is rejected so a disconnected monitor doesn't strand the window off-screen.

4. Two new unit tests cover FrameProcessor's drops + duplicates accounting. 76/76 unit tests pass (was 74).
2026-05-08 13:59:14 -04:00