Skip to content

Test coverage: UI-automation input helpers to >=95% - #649

Merged
Alexandre Zollinger Chohfi (azchohfi) merged 5 commits into
mainfrom
azchohfi-tests-uia-input
Jul 16, 2026
Merged

Alexandre Zollinger Chohfi (azchohfi) merged 5 commits into
mainfrom
azchohfi-tests-uia-input

Conversation

@azchohfi

Copy link
Copy Markdown
Collaborator

What

Raises per-file test coverage to ≥95% for the UI-automation input helpers, part of the CLI coverage initiative (#630). All 10 files in scope now meet the bar:

File Coverage
Helpers/KeyboardInput.cs 95.7%
Helpers/MouseInput.cs 95.8%
Helpers/ForegroundGuard.cs 98.1%
Services/SystemUiQuery.cs 99.2%
Helpers/GestureTargeting.cs 100%
Helpers/RealOwnedWindowFinder.cs 100%
Helpers/RealMouseInput.cs 100%
Helpers/RealKeyboardInput.cs 100%
Helpers/RealForegroundGuard.cs 100%
Services/ISystemUiQuery.cs 100%

How

  • Tests only + minimal, behavior-preserving product test-seams. The product changes extract each helper's native P/Invoke defaults (SendInput, PostMessage, MapVirtualKey, SetCursorPos, GetForegroundWindow, etc.) into named methods and add an internal static ResetNativeSeams() that restores those production delegates. No behavior change — production still calls the same native APIs.
  • Deterministic native-seam fakes are installed in [TestInitialize] (within-class isolation); [TestCleanup] calls the new ResetNativeSeams() so process-global seam state is restored to production after each [DoNotParallelize] class finishes, preventing faked state from leaking to later tests that exercise the real path.
  • Added delegation tests for the RealKeyboardInput and RealForegroundGuard thin adapters (matching the existing RealMouseInput test).

Policy

No [ExcludeFromCodeCoverage], no coverage.runsettings edits. The few remaining uncovered lines are innermost native/SendInput boundaries.

Validation

  • Debug (product + tests) build 0W/0E.
  • Release both projects individually (-p:UseSharedCompilation=false -nodeReuse:false) 0W/0E each.
  • Input test classes: 61 passed / 0 failed.
  • Reviewed with the repo pr-review skill (7 specialists + GPT multi-model) before opening; the multi-model HIGH test-isolation finding and a vacuous test were fixed in this branch.

Co-authored-by: Copilot App 223556219+Copilot@users.noreply.github.com

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
pr-review follow-ups on the input-helper coverage work:

- Fix a test-isolation defect (multi-model HIGH): KeyboardInput, MouseInput and
  ForegroundGuard [TestCleanup] reset their process-global native seams to test
  fakes/no-ops, leaking faked state to any later test that exercises the real
  path. Add internal ResetNativeSeams() to each product helper (extracting the
  production P/Invoke defaults to named methods) and point [TestCleanup] at it so
  cleanup restores real delegates. Deterministic fakes stay in [TestInitialize]
  for within-class isolation. Mirrors the existing SystemUiQuery/RealOwnedWindowFinder
  pattern.
- Fix a vacuous RealOwnedWindowFinder test (asserted nothing) to assert a stable,
  idempotent native read.
- Add delegation tests for the RealKeyboardInput and RealForegroundGuard thin
  adapters (were 0%, now 100%), matching the existing RealMouseInput test.

Debug + Release (both projects) build 0W/0E. Input cluster all >=95%
(KeyboardInput 95.7%, MouseInput 95.8%, ForegroundGuard 98.1%, SystemUiQuery
99.2%, adapters/gesture/owned-window 100%). 61 input tests pass.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 16, 2026 04:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds native seams and tests to raise UI-automation input-helper coverage above 95%.

Changes:

  • Extracts Win32 calls behind resettable test seams.
  • Adds deterministic helper and adapter tests.
  • Expands gesture-targeting coverage.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
Services/SystemUiQuery.cs Adds native query seams.
Helpers/RealOwnedWindowFinder.cs Adds window-enumeration seams.
Helpers/MouseInput.cs Extracts and tests input-building logic.
Helpers/KeyboardInput.cs Extracts keyboard batching and native calls.
Helpers/ForegroundGuard.cs Adds foreground-window seams.
SystemUiQueryTests.cs Tests process and window queries.
RealOwnedWindowFinderTests.cs Tests owned-window filtering.
MouseInputTests.cs Tests mouse gestures and failures.
KeyboardInputTests.cs Tests keyboard batching and failures.
GestureTargetingTests.cs Tests stable-target resolution.
ForegroundGuardTests.cs Tests foreground classification and adapter delegation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +16 to +17
[TestCleanup]
public void Cleanup() => ResetSeams();

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed in b2a1c56. Cleanup() now calls the product SystemUiQuery.ResetNativeSeams(), which restores the real native delegates, instead of the local ResetSeams() fake-installer. Since the seams are static, teardown no longer leaks fakes into other test classes. [TestInitialize] still installs the deterministic fake base per test.

Comment on lines +16 to +17
[TestCleanup]
public void Cleanup() => ResetSeams();

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in b2a1c56 — same fix as the SystemUiQuery cleanup. Cleanup() now calls RealOwnedWindowFinder.ResetNativeSeams() to restore the production delegates, so the static seams do not persist fakes across classes. It also brings RealOwnedWindowFinder.cs to 100%, since ResetNativeSeams now runs on every cleanup.

Comment on lines +90 to +94
// Enumerating the first top-level window from a null handle must be a stable, side-effect-free
// read: two back-to-back native calls return the same handle (covers the production delegate
// without depending on which specific window happens to be topmost on the agent).
var firstTopLevel = RealOwnedWindowFinder.s_findNextTopLevelWindow(HWND.Null);
Assert.AreEqual(firstTopLevel, RealOwnedWindowFinder.s_findNextTopLevelWindow(HWND.Null));

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed — fixed in b2a1c56. The two live FindWindowEx(Null) calls were Z-order-dependent and could differ if the topmost window changed between them. Now the production enumeration delegate is invoked once for coverage with no assertion on the volatile handle; the deterministic Null-handle reads (visible=false, owner=Null, pid=0, empty text) remain the stable assertions.

@github-actions

github-actions Bot commented Jul 16, 2026 •

Copy link
Copy Markdown
Contributor

⏳ Build in progress — metrics below are from a previous commit and will update when the current build finishes.

Build Metrics Report

Binary Sizes

Artifact Baseline Current Delta
CLI (ARM64) 36.75 MB 36.77 MB 📈 +23.0 KB (+0.06%)
CLI (x64) 36.93 MB 36.95 MB 📈 +18.5 KB (+0.05%)
MSIX (ARM64) 15.35 MB N/A N/A
MSIX (x64) 16.30 MB N/A N/A
NPM Package 32.04 MB N/A N/A
NuGet Package 32.07 MB N/A N/A

Test Results

✅ 0 passed out of 0 tests in 0.0s (-3246 tests, -626.5s vs. baseline)

Test Coverage

❌ 0% line coverage, 0% branch coverage · ⚠️ -83.6% vs. baseline

CLI Startup Time

44ms median (x64, winapp --version) · ✅ -7ms vs. baseline


Updated 2026-07-16 05:28:38 UTC · commit b2a1c56 · workflow run

…ssertion

Addresses the Copilot auto-review findings on PR #649:

- SystemUiQueryTests / RealOwnedWindowFinderTests [TestCleanup] called the local
  ResetSeams() helper, which installs FAKE delegates. Because the seams are static,
  the last test in each class left fakes installed process-wide, which could leak into
  other test classes that exercise the real SystemUiQuery / RealOwnedWindowFinder. Point
  Cleanup at the product ResetNativeSeams() so teardown restores the real native
  delegates. [TestInitialize] still installs the deterministic fake base for each test.
  (Bonus: RealOwnedWindowFinder.cs is now 100% since ResetNativeSeams runs every cleanup.)

- RealOwnedWindowFinderTests.NativeSeams_HandleNullWindowWithoutMutation asserted that two
  back-to-back live FindWindowEx(Null) calls return the same handle. The topmost window is
  Z-order-dependent and can change between calls, so this was flaky. Invoke the production
  enumeration delegate once for coverage instead; keep the deterministic Null-handle reads
  (visible=false, owner=Null, pid=0, text="") as the stable assertions.

Coverage held: SystemUiQuery.cs 99.2%, RealOwnedWindowFinder.cs 100%. Debug 0W/0E; the two
affected classes pass 13/13.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…iAutomation fake

Main #600 (ui touch/pen) added TryGetWindowRect(long, out PointerRect) to
IUiAutomationService. This branch's GestureTargetingTests QueueUiAutomation fake predates it,
so the head+main merge build failed (CS0535). Implement it as a safe no-op (returns false /
default rect) since the gesture-targeting tests resolve elements via FindSingleElementAsync and
do not depend on a window rect. FakeUiAutomationService already implements it (from main).

Debug + Release(both) 0W/0E; 69 gesture/input/system tests pass.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@azchohfi
Alexandre Zollinger Chohfi (azchohfi) merged commit 5c334c8 into main Jul 16, 2026
20 checks passed
@azchohfi
Alexandre Zollinger Chohfi (azchohfi) deleted the azchohfi-tests-uia-input branch July 16, 2026 05:47
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.

2 participants