Skip to content

Test coverage: UI Automation service and capture stack (issue #630)#669

Merged
azchohfi merged 11 commits into
mainfrom
azchohfi-tests-uia-coverage
Jul 16, 2026
Merged

Test coverage: UI Automation service and capture stack (issue #630)#669
azchohfi merged 11 commits into
mainfrom
azchohfi-tests-uia-coverage

Conversation

@azchohfi

Copy link
Copy Markdown
Collaborator

What & why

Raises per-file test coverage for the UI-Automation service and its capture/record stack toward the >=95% bar from issue #630. This is a test-coverage PR: the bulk is new tests plus a small set of behavior-preserving internal static seams that let real COM-fault paths be driven deterministically. No [ExcludeFromCodeCoverage], no coverage.runsettings exclusions, no service exclusions - hard-to-test paths get real tests, minimal seams, or a source-documented genuine ceiling.

Net: 19 files, +4,295/-34 (mostly new RealUiAutomationTests.* partials, UiAutomationServicePureTests, the live UiaTestFixture, and DesktopTestHelpers).

Coverage - in-scope product files

File Coverage Notes
UiAutomationService.cs 95.5% (1472/1541) core navigation/resolve/patterns
UiAutomationService.ValueSetStrategy.cs 100% (44/44) RangeValue/Legacy COM fallback arms now covered via ComProxy

The 69 residual lines in UiAutomationService.cs are genuine ceilings: COM-fault catch {} swallows, defensive breaks during live TreeWalker walk-ups, and native owned-window enumeration (GetAllAppWindows) that in-process UIA already resolves through its primary pass. Each is a single native-boundary arm, documented at the call site.

Documented native ceilings (GPU / WGC / Media Foundation)

These files exercise the genuinely native capture+encode stack - GPU frame delivery, a live Windows.Graphics.Capture session, and Media Foundation sink writers - which cannot run deterministically/headlessly on a shared desktop. Interactive-only tests cover what they can; the residual is a hardware/OS boundary, documented in-source with <remarks>:

File Coverage
WgcCapture.cs 85.2%
WgcCapture.Record.cs 6.7%
UiAutomationService.Screenshot.cs 73.1%
UiAutomationService.Record.cs 64.3%
Mp4SinkWriterEncoder.cs 84.8%

Approach

  • Real-UIA fixture tests. A live WinForms UiaTestFixture (buttons, text/value/multiline, checkboxes, list, scroll panel + nested children, combo, tabs, tree, slider, progress, numeric, owned window) drives the service against real providers. Real-UIA tests self-skip via Assert.Inconclusive off an interactive desktop, so CI is never blocked - no assertion is suppressed.
  • Behavior-preserving seams. internal static Func seams (e.g. s_getRootElement, s_elementFromHandle, s_getDesktopRootElement, s_getMainWindowHandleForProcessId) default to the exact original expression and are restored by ResetNativeSeams() in [TestCleanup]; production never reassigns them. ComProxy<T> (DispatchProxy) fakes the COM interfaces to fault-inject specific arms - always against Environment.ProcessId, never a foreign PID.

Review & validation

  • Earlier pr-review findings on this branch are fixed (f5bfa899): a WGC grabber leak on the StartGrabber catch path, plus assertion-strengthening on Scroll/NumericUpDown fallback-routing tests.
  • A multi-model cross-check (GPT family) on the coverage delta flagged that ResetNativeSeams() was not the single source of truth for all UIA seams; consolidated in 395d74fb (screenshot seams now reset centrally; duplicated per-class reflection resets removed). No leak existed, but the reset contract is now complete.
  • Builds: Debug solution 0W/0E; Release both projects individually 0W/0E (warnings-as-errors).
  • Scoped UIA suite: 591 total, 0 failed, 1 skipped (the interactive-only Record_WebView2StyleCompositedContent test); the real-UIA tests ran for real. New COM-proxy tests re-run clean across repeats (deterministic).

Base note

Branches off current main, which includes the #654 revert of the #629/#647 NuGet-client migration. No UIA scope overlaps that revert.

azchohfi and others added 11 commits July 15, 2026 22:44
Split RealUiAutomationTests into partial files under the 1000-line cap and harden the ambiguous-selector assertion.

Added deterministic pure coverage for screenshot retry/letterbox seams, WGC support/blank/HRESULT helpers, record sizing/retarget/frame helpers, MP4 publish/validation/complete paths, and UiRecordCommand short-description/COM failure handling.

Final filtered coverage observed: UiAutomationService.cs 80.0%; UiAutomationService.Record.cs 29.1%; UiAutomationService.Screenshot.cs 81.0%; UiAutomationService.ValueSetStrategy.cs 88.6%; WgcCapture.cs 49.8%; WgcCapture.Record.cs 6.3%; Mp4SinkWriterEncoder.cs 85.2%; RecordModels.cs 100.0%; UiRecordCommand.cs 97.7%.

Documented issue #630 ceilings on innermost native WGC/D3D/GDI/MF boundaries and retained real gated capture attempts for hosts that can exercise them.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add deterministic recorder seams for WGC grabbers and MP4 encoders, exercise real in-process record paths, and document native UIA/WGC/Media Foundation coverage ceilings for the remaining host-bound arms.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- H1 (WgcCapture.Record.StartGrabber): dispose pool+session in the catch
  before rethrow so a fault after pool/session creation can't leak the WGC
  frame pool or capture session (mirrors FrameGrabber.Dispose order).
- M1/L1 (UiAutomationService): remove 27 identical copy-paste ceiling
  <remarks> blocks (several on fully-covered methods, one duplicated) and
  replace with a single accurate class-level <remarks>.
- M3 (ScrollIntoView test): assert the child's VerticalScrollPercent actually
  increases (before < after) instead of only "no exception".
- M2 (NumericUpDown test): construct the service with a capturing logger and
  assert the value-set strategy walks ValuePattern -> RangeValuePattern ->
  LegacyIAccessible (both pattern strategies log a caught failure), a real
  deterministic assertion of the fallback routing instead of "no throw".
- L2: correct a misleading HScrollBar test comment.

Test-only + one small product leak fix; no behavior change. Coverage
unchanged (documented native ceilings hold).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add real UIA coverage for edge selector, window, slug, and pattern paths with resettable fault-injection seams for native COM failure arms.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The seam-wrapper methods pass 'this' to the static seam, which already
satisfies the analyzer; the _ = _logger; discards were dead noise.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add real fixture controls and targeted COM seam tests to cover additional UiAutomationService branches.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Multi-model review finding: ResetNativeSeams() reset only the core
navigation seams, while the screenshot seams (s_captureFromWindow,
s_captureFromScreenScaled, s_foregroundWindowForBlankRetry,
s_sleepForBlankRetry) declared in the Screenshot partial were reset
only by duplicated per-test-class cleanup code. No leak existed (each
class reset the seams it touched), but the reset contract was
incomplete and duplicated.

Make ResetNativeSeams the single source of truth for every
UiAutomationService static seam by resetting the four screenshot seams
to their declared defaults, then drop the now-redundant per-class
resets: the reflection-based block in RealUiAutomationTests cleanup and
the four resets plus their two orphaned GetReal* reflection helpers in
UiAutomationServicePureTests cleanup. Behavior-preserving and test-only;
UiAutomationService.cs coverage holds at 95.5%.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
UiAutomationService.ValueSetStrategy.cs documented the RangeValuePattern
success line and the LegacyIAccessible COM-failure catch arm as coverage
ceilings, claiming the deterministic WinForms fixture could not expose
them. That is no longer accurate: SetValueAsync resolves its COM element
through the seam-injectable ResolveComElement, so the same ComProxy COM
fault-injection used elsewhere in the suite drives these arms directly.

Add two targeted tests via SetValueAsync:
- RangeValuePattern success after ValuePattern is unavailable (proxy
  ValuePattern throws, proxy RangeValuePattern.SetValue records the value).
- LegacyIAccessible SetValue COM fault is logged and surfaces the
  send-keys hint (non-numeric text skips RangeValue; proxy legacy pattern
  throws), asserting both the thrown message and the captured debug log.

Remove the stale "coverage ceiling" remarks now that both arms are
covered. UiAutomationService.ValueSetStrategy.cs goes 88.6% -> 100%.
Test-only plus doc-comment removal; no behavior change.

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

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@azchohfi
azchohfi merged commit bad8464 into main Jul 16, 2026
21 of 27 checks passed
@azchohfi
azchohfi deleted the azchohfi-tests-uia-coverage branch July 16, 2026 23:48
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