code-coverage-calculation
Skill8.6k starsChanged 38 days agoMITView on GitHub
EXPERIMENTAL. Calculate code coverage of a WinUI control or component (for example "calculate coverage of control TitleBar") by running only that component's tests on a local Hyper-V VM against the local build. Supports controls in Microsoft.UI.Xaml.Controls.dll and Microsoft.UI.Xaml.Controls.Tabular.dll, and dxaml types in Microsoft.ui.xaml.dll. Reports per-file and per-function line coverage that matches the ADO Code Coverage tab. Use for "calculate/measure/get coverage of <control>", "how much do <control>'s tests cover", or "coverage before/after my tests" when you have a local build and a VM.
We split this skill into the rules it gives an agent
21 rules. About 0 are common, 4 are distinctive, and 17 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
17
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 17
All commands run from the repo root.
- Very specific: line 34
Look for cached credentials.
- Very specific: line 43
If two VMs share one CacheFile (for example Test-VM and Test_VM), don't offer the cache for either.
- Very specific: line 45
Use ask_user every time:
- Distinctive: line 46
Cached credentials exist: ask "Is this the VM to use?" Offer one choice per VM and username listed above, plus "Enter different VM details".
- Very specific: line 48
No cache, or the user chooses different details: ask for the VM name and VM username (the plain account name as shown on the VM, with no .\ …
- Distinctive: line 50
If the user declines or cancels, stop.
- Very specific: line 51
Run tools\Set-VmCredential.ps1 -VMName <vm> -UserName <user> (a shared repo tool):
- Distinctive: line 59
If the script fails (VM missing or stopped, bad password, no active desktop), report the message, ask the user to fix it or give new …
- Very specific: line 69
Module: if controls\Tabular.ProjectImports.targets imports dev\<F>\<F>.vcxitems (today: TableView, TabularShaping, ShapedItemsSource, …
- Very specific: line 76
Prefer one wildcard that covers every class, usually *.<F>Tests.*.
- Very specific: line 78
If no single wildcard covers them all, pass several filters (-TestFilter 'a','b').
- Distinctive: line 80
If the folder has no tests, tell the user and ask which tests to run.
- Very specific: line 101
Use ask_user to present the proposed source files and regex, test classes and filter(s), and module Microsoft.ui.xaml.dll.
- Very specific: line 105
C. Found in neither place: ask the user which source folder and tests to use.
- Very specific: line 123
Add -RefreshPayload if TestPayload\x64chk is missing or older than the build output.
- Very specific: line 125
Add -MoveSessionToConsole when the host is an RDP or Cloud PC session ($env:SESSIONNAME -like 'RDP-*').
- Very specific: line 128
Run it async with a long wait.
- Very specific: line 131
Run from the repo root in PowerShell, invoking the script directly.
- Very specific: line 144
If restoring the payload or VM fails, the command fails (after writing the report, if coverage was collected) and instrument-state.json is …
- Very specific: line 150
Check the test summary. If Total=0, the filter matched nothing.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
WinUI component coverage from a local VM test run
Agent workflow (follow in order; every gate is mandatory)
All commands run from the repo root. <skill> = .github\skills\code-coverage-calculation.
Gate 0 - Prerequisites (check; stop and tell the user on failure)
| Check | How | If missing |
Local build of the flavor (default amd64chk), from the current branch | The module DLL exists under BuildOutput\bin\amd64chk\Product\, and for MUXC/Tabular the link log BuildOutput\obj\amd64chk\controls\dev\dll (or dll-tabular) \**\link.command.1.tlog exists | Ask before building (10+ min), then run .\initrun.ps1 .\build.cmd /q from the repo root. |
| VS Enterprise code coverage | Microsoft.CodeCoverage.Console.exe under %ProgramFiles%\Microsoft Visual Studio | Stop; the user must install it. |
dotnet-coverage | Get-Command dotnet-coverage | Tell the user: dotnet tool install --global dotnet-coverage |
| Hyper-V rights | Get-VM succeeds | Stop. Ask the user to add their account (from whoami) to Hyper-V Administrators in an elevated PowerShell window, then sign out and back in. Never elevate or add group members yourself. |
Gate 1 - VM details (strict: never start a run without them)
Before every coverage run, the user must explicitly confirm the VM or enter its details in this session. Never pick a VM silently, even if only one credential is cached. Never reuse a VM name, username or password from memory, an earlier session, or an earlier run without asking again.
- Look for cached credentials. Match them against the real VM names, because the cache file name
replaces non-alphanumeric characters with
_and can't be turned back into the VM name. This shows the username only, never the password:
If two VMs share oneGet-VM | ForEach-Object { $f = Join-Path $env:USERPROFILE ".winui-test\vmcred-$($_.Name -replace '[^a-zA-Z0-9]','_').xml" if (Test-Path $f) { [pscustomobject]@{ VM = $_.Name; State = $_.State; UserName = (Import-Clixml $f).UserName; CacheFile = Split-Path $f -Leaf } } }CacheFile(for exampleTest-VMandTest_VM), don't offer the cache for either; ask for details and re-enter the password (-Force). - Use
ask_userevery time:- Cached credentials exist: ask "Is this the VM to use?" Offer one choice per VM and username listed above, plus "Enter different VM details".
- No cache, or the user chooses different details: ask for the VM name and VM username
(the plain account name as shown on the VM, with no
.\orVM\prefix). - If the user declines or cancels, stop. Do not continue with a default.
- Run
tools\Set-VmCredential.ps1 -VMName <vm> -UserName <user>(a shared repo tool):- For new details, add
-Force. The script asks for the password in a separate window (never in chat; chat text is kept in session history) and writes the encrypted per-user cache%USERPROFILE%\.winui-test\vmcred-<vm>.xml. This is the cachetools\run-tests-on-vm.ps1and Steps 3-4 read; Step 3 does not pass-Credentialto the runner, so the cache must exist. - For a confirmed cached VM, run it without
-Force. It validates without prompting. - Either way it checks that the VM exists and is Running, that the logon works, and that the user has an Active desktop session. A new credential replaces the cache only after it validates.
- For new details, add
- If the script fails (VM missing or stopped, bad password, no active desktop), report the message, ask the user to fix it or give new details, and repeat this gate. Do not continue.
Gate 2 - Resolve the component and its tests
A. controls\dev (Microsoft.UI.Xaml.Controls.dll or Microsoft.UI.Xaml.Controls.Tabular.dll)
- Folder: match the name case-insensitively against
controls\dev\*folders. If there's no match, searchcontrols\dev\*\*.idlforruntimeclass <Name>and use that folder (for exampleItemsRepeaterresolves toRepeater). If there are zero or several candidates, ask the user and offer the candidates. Module: ifcontrols\Tabular.ProjectImports.targetsimportsdev\<F>\<F>.vcxitems(today: TableView, TabularShaping, ShapedItemsSource, GroupedSourceAdapter, HierarchicalSourceAdapter, SortIndicator, ResizeGripper), the code is inMicrosoft.UI.Xaml.Controls.Tabular.dll: pass-Module Microsoft.UI.Xaml.Controls.Tabular.dll. Otherwise it'sMicrosoft.UI.Xaml.Controls.dll(the default). - Tests: list the
[TestClass]classes (with their namespaces) incontrols\dev\<F>\APITests\**\*.csandcontrols\dev\<F>\InteractionTests\**\*.cs. TAEF test names are<namespace>.<class>.<method>, andruntestsselects@Name='*<filter>'.- Prefer one wildcard that covers every class, usually
*.<F>Tests.*. It covers both theApiTestsandInteractionTestsclasses, and namespaces such as...ApiTests.RepeaterTests.*. - If no single wildcard covers them all, pass several filters (
-TestFilter 'a','b'). Each runs with its own collector, and the results are merged and deduplicated in the report. - If the folder has no tests, tell the user and ask which tests to run.
- Prefer one wildcard that covers every class, usually
-ComponentPathRegex: take everyruntimeclass<RC>declared incontrols\dev\<F>\*.idland match the folder plus both kinds of generated sources:\\controls\\dev\\<F>\\|\\controls\\dev\\Generated\\(<RC1>|<RC2>|...)\.|\\dll(-tabular)?\\generated\\(.+\\)?(<RC1>|<RC2>|...)\.g\.The second part coverscontrols\dev\Generated\<RC>.properties.*and the third covers the build-generatedBuildOutput\obj\<flavor>\controls\dev\dll\generated\...\<RC>.g.cpp/.h(ordll-tabular\generated) files.- Show the resolved plan (folder, module, test classes, filter(s), regex), then proceed. Ask only if something is ambiguous.
- The build must contain those tests. Before instrumenting, the orchestrator lists the matching tests in
TestPayload\<flavor>with TAEF (the same selectionruntestsuses on the VM) and stops in seconds if a filter matches none. That usually meansBuildOutputwas built from an older commit or another branch. Tell the user, ask before rebuilding (.\initrun.ps1 .\build.cmd /q), then rerun with-RefreshPayload.
B. Not in controls\dev: investigate dxaml (MUX, Microsoft.ui.xaml.dll) and get approval
- Sources: search
dxaml\xcpfor the type, for examplecore\core\elements\<Name>.cpp,core\inc\<Name>.h,dxaml\lib\<Name>_Partial.*,dxaml\lib\winrtgeneratedclasses\<Name>.g.*,components\**, andcore\controls\generated\C<Name>*. Decide which are in scope (for example whetherButtonBasecounts forButton). - Tests:
dxaml\test\native\external\<area>\<name>\(C++ TAEF; names look likeMicrosoft::UI::Xaml::Tests::Controls::<Name>::<Class>::<Method>). Note each class'sHosting:Mode;runtestscannot mix hosting modes in one filter, so use one filter per mode. - Use
ask_userto present the proposed source files and regex, test classes and filter(s), and moduleMicrosoft.ui.xaml.dll. Warn that MUX is about 71 MB, so the first instrumentation is likely to take well over 40 minutes. Do not run until the user approves. Revise the plan with their feedback.
C. Found in neither place: ask the user which source folder and tests to use. Other DLLs (for example
Microsoft.UI.Xaml.Phone.dll) aren't supported yet; say so instead of measuring a different module.
Tell the user what the run does on the VM (before every run)
The run makes changes on the test VM, so say this once before starting:
- It creates
C:\WinUICoverage(coverage tools, logs and output) and runs short-lived scheduled tasks as the VM user. With-MoveSessionToConsoleit also runstsconas SYSTEM to move the session to the console. - It opens the coverage collector's named pipe (
\\.\pipe\CodeCoverage.pipe.<id>) with a NULL DACL, so low-integrity test processes can report coverage. Any local user on the VM can connect to that pipe until the run ends. This is intended for a dedicated test VM; don't use it on a shared machine. - It temporarily replaces the module in the local
TestPayloadand in the VM's deployed payload with the instrumented copy, and restores both afterwards (hash-checked).BuildOutputand sources are never changed.
Run
- Output:
<repo>\BuildOutput\Coverage\<flavor>\<Component>by default (git-ignored withBuildOutput). Itswork\folder holds the relinked and instrumented DLLs and the payload backups (several hundred MB). - Add
-RefreshPayloadifTestPayload\x64chkis missing or older than the build output. A failed refresh stops the run. - Add
-MoveSessionToConsolewhen the host is an RDP or Cloud PC session ($env:SESSIONNAME -like 'RDP-*'). - Tell the user the expected time first (about 30-60 min the first time for MUXC, mostly instrumentation; a few
minutes for the 6.5 MB Tabular DLL; about 6-10 min with the cache).
Run it async with a long wait. Never stop the process during Step 2 or 3; the restore runs in
finally, and if a run is killed anyway, the next run restores the payload before doing anything else.
Run from the repo root in PowerShell, invoking the script directly. Don't use pwsh -File: it turns
'a','b' into a single string.
& .\.github\skills\code-coverage-calculation\scripts\Invoke-WinUIVmCoverage.ps1 `
-RepoRoot (Get-Location).Path -VMName <vm> -TestFilter '<filter>'[,'<filter2>'] `
-ComponentName <F> -ComponentPathRegex '<regex>' `
-Module <Microsoft.UI.Xaml.Controls.dll|Microsoft.UI.Xaml.Controls.Tabular.dll|Microsoft.ui.xaml.dll> `
[-RefreshPayload] [-MoveSessionToConsole]Report
- If restoring the payload or VM fails, the command fails (after writing the report, if coverage was
collected) and
instrument-state.jsonis kept. Tell the user prominently, and offer to rerun<skill>\scripts\Step4-Restore-Payload.ps1 -RepoRoot <repo> -WorkDir <OutputDir>\work -VMName <vm>(or simply rerun the coverage command, which restores first). - From
report-<ts>\coverage-summary.md, present the component total, the per-file table, and the uncovered and partially covered functions. Point toTreeReport\coverage-tree.htmland the CSVs. - Check the test summary. If
Total=0, the filter matched nothing; fix the filter instead of reporting 0 %.
Reference
Measures which lines of one component your selected tests execute. It doesn't need a pipeline
run: it uses your local build and the same Hyper-V VM and runner (tools\run-tests-on-vm.ps1) you
already use for WinUI tests. Everything it needs is in this folder.
How it works
- Instrumentable MUXC: static native instrumentation needs CV and FIXUP debug info
(
/DEBUGTYPE:CV,FIXUPwith/INCREMENTAL:NO), which a chk MUXC link doesn't emit. Step 1 relinks a copy with those flags from the recorded link command, without touching the repo orBuildOutput. - Collection: the DLL is instrumented once with a per-module session id and copied over every
payload copy, together with
static_covrun*.dll. On the VM, a server-mode collector listens on a named pipe thatlib\Set-CoveragePipeAcl.ps1opens to low-integrity test processes. Shutting the collector down flushes the.coveragefile. - Accurate numbers: merging native
.coveragefiles to Cobertura repeats every line once per input file, so naive totals undercount coverage.lib\Repair-CoverageDuplicates.ps1andlib\Split-CoverageByModule.ps1keep one entry per (file, line), which matches the Azure DevOps Code Coverage tab.lib\Get-FunctionCoverage.ps1adds per-function detail from the native XML merge, and theBuild-*TreeReport.ps1scripts render single-file HTML reports. The PDB is only needed at instrument time.
Quick start
cd <repo-root>\.github\skills\code-coverage-calculation\scripts
.\Invoke-WinUIVmCoverage.ps1 `
-RepoRoot <repo-root> `
-VMName <vm> `
-TestFilter '*.TitleBarTests.*' `
-ComponentName TitleBar `
-ComponentPathRegex '\\controls\\dev\\TitleBar\\|\\Generated\\TitleBar|\\generated\\Controls\\TitleBar' `
-MoveSessionToConsole `
-BaselinePerFileCsv '<baseline-run>\PerModule\Microsoft.UI.Xaml.Controls\corrected-per-file.csv' `
-BaselineLabel 'Full test pass'Output goes to <repo-root>\BuildOutput\Coverage\amd64chk\TitleBar unless you pass -OutputDir. If the baseline came from another checkout, also pass -BaselineRepoRoot <that checkout's root>.
Open <OutputDir>\report-<timestamp>\coverage-summary.md. Other outputs in that folder:
component-per-file.csvcomponent-functions.csvTreeReport\coverage-tree.htmlPerModule\<Module>\corrected-per-file.csv(whole module)
Prerequisites
- Local build: a full local build of the flavor you test (default
amd64chk), so thatBuildOutput\obj\...\link.command.1.tlog, the objs and the PDB exist. Also an existingTestPayload\x64chk, created by any earliertools\run-tests-on-vm.ps1run, or pass-RefreshPayload. - Visual Studio Enterprise (host): supplies
Microsoft.CodeCoverage.Console.exefor instrument, collect and shutdown, and the MSVC toolset that built the objs. dotnet-coverage:dotnet tool install --global dotnet-coverage, used for the merge.- VM access:
- A running Hyper-V VM with the test user logged on, an unlocked interactive desktop, and the WinUI test prerun already done (any earlier
run-tests-on-vm.ps1run does this). - The host account must be a local admin or a member of Hyper-V Administrators.
- The VM credential must be cached in
%USERPROFILE%\.winui-test\vmcred-<VM>.xml, the same cacherun-tests-on-vm.ps1uses.
- A running Hyper-V VM with the test user logged on, an unlocked interactive desktop, and the WinUI test prerun already done (any earlier
- No VS or dotnet needed on the VM: the collector tools are staged to
C:\WinUICoverage\CoverageToolautomatically.
What it does (and why)
| Step | Script | Notes |
| 1 | Step1-New-InstrumentableDll.ps1 | MUXC and Tabular (Microsoft.UI.Xaml.Controls.Tabular.dll, relinked from controls\dev\dll-tabular). chk MUXC is not instrumentable: the tool prints "Unable to obtain debug information. Link with the /PROFILE linker switch." and then exits 0 with the image untouched. It needs /DEBUGTYPE:CV,FIXUP with /INCREMENTAL:NO at link time, and this skill never edits repo files, so the script re-runs the exact link command MSBuild recorded (link.command.1.tlog) with /DEBUGTYPE:CV,FIXUP added and /INCREMENTAL:NO. /OUT, /PDB, /IMPLIB and /MAP are redirected to work\relink, and /WINMD:NO is set. It takes about 15 s, and BuildOutput is never touched. MUX (Microsoft.ui.xaml.dll) already links with /debugtype:cv,fixup,pdata and skips this step. |
| 2 | Step2-Instrument-Payload.ps1 | Static native instrumentation with a fresh 16-hex session id. This is slow for a 38 MB chk DLL (about 20-50 min), so the result is cached in work\instrumented, keyed by the input DLL's SHA256, and reused on later runs together with its baked-in session id. The cache is reused only while the tool that instrumented it still exists at the same version. The script catches the "exit 0 but not instrumented" case. It backs up every payload copy and writes instrument-state.json before overwriting anything (so an interrupted run can always be restored), then overwrites every payload copy of the DLL, plus static_covrun64.dll, because each test app loads its own co-located copy (Test\UnpackagedApps\MUXControlsTestApp\). Backups are refreshed from the payload whenever a copy isn't instrumented, so a rebuilt payload is never restored to an older DLL. |
| 3 | Step3-Invoke-VmCoverageRun.ps1 | Stages the collector on the VM once. It starts collect --server-mode --session-id <sid> as the VM user through an interactive scheduled task, waits for \\.\pipe\CodeCoverage.pipe.<sid>, and sets a NULL DACL on it. It then runs initrun.ps1 .\tools\run-tests-on-vm.ps1 -SkipPayload <filter>. -SkipPayload only stops the runner from regenerating TestPayload from BuildOutput (which would overwrite the instrumented DLLs); the runner still copies the changed payload files to the VM and runs the tests on the desktop. In finally it calls shutdown <sid> so the collector writes the .coverage file, downloads it and the collector log (also when the run failed), and closes the VM session. |
| 4 | Step4-Restore-Payload.ps1 | Always runs, from finally, and again at the start of the next run if a previous run was killed before restoring. It restores every original DLL (copies that were never overwritten are skipped), hash-verified, removes static_covrun*.dll, and does the same in the VM's deployed payload. Each distinct original is restored to its own copies. If any VM copy doesn't match afterwards, it fails and keeps instrument-state.json, so you can simply run it again. A restore failure makes the whole command fail. |
| 5 | Step5-Get-ComponentCoverage.ps1 | Merges the coverage to Cobertura (dotnet-coverage merge -f cobertura) and applies the per-module (file, line) dedup (lib\Split-CoverageByModule.ps1), the same correction that matches the ADO tab. It then filters to the component by -ComponentPathRegex and optionally compares with a baseline corrected-per-file.csv. Paths are matched repo-relative: the checkout root (-RepoRoot, or -BaselineRepoRoot for a baseline from another checkout) or a build-agent root such as C:\__w\1\s\ is removed, the report warns if the baseline matches none or under half of the component files, and x86chk versus amd64chk doesn't matter. It also produces function-level coverage (lib\Get-FunctionCoverage.ps1) and the HTML tree (lib\Build-CoverageTreeReport.ps1). |
You can run the steps one at a time. Each writes its state or results under <OutputDir>\work.
Timing
- First run: about 30-60 min, almost all of it Step 2 instrumenting a 38 MB chk MUXC (20-50 min; it runs on a single core). The rest is a few seconds to relink, then deploy, the tests, flush and the report.
- Tabular (6.5 MB): instrumentation takes only a few minutes.
- Later runs with an unchanged build: about 6-10 min. The relink and the instrumented DLL are both reused from
<OutputDir>\work. - Report: parsing the Cobertura and native XML takes about 1-2 min each; skip the second with
-SkipFunctionCoverage.
Verified result (TitleBar, 2026-10-06)
-TestFilter '*.TitleBarTests.*' on a local Hyper-V VM (Windows 11, amd64chk): 24/24 tests passed, and the collector produced an 88 MB .coverage file. These are the numbers from the full skill run, next to a baseline from a CI coverage run of all tests:
| File | TitleBar tests only (this skill) | CI coverage run (all tests) |
controls\dev\TitleBar\TitleBar.cpp | 98.07 % (507/517) | 10.64 % (55/517) |
controls\dev\TitleBar\TitleBarAutomationPeer.cpp | 100 % (17/17) | 0 % (0/17) |
controls\dev\Generated\TitleBar.properties.cpp | 90.23 % (157/174) | 28.74 % (50/174) |
| All 15 TitleBar source files | 81.03 % (773/954) | 23.69 % (226/954) |
Of 45 functions in the TitleBar .cpp files, 40 are fully covered, 4 partially, and 1 not at all (OnWindowRectChanged). Afterwards, the payload, the VM and BuildOutput were all verified back at their original hashes.
Tabular module (TableView, 2026-10-20): -Module Microsoft.UI.Xaml.Controls.Tabular.dll -TestFilter '*.TableViewSortingTests.*': 35/35 tests passed in 3 min 41 s end to end (instrumenting the 6.5 MB DLL took 45 s). From that one test class, TableView was at 3557/11779 lines (30.2 %), with TableView.cpp at 63.8 %. The payload and the VM were restored afterwards.
Gotchas (learned the hard way)
- Host session disconnects (Cloud PC / RDP): if the host's session disconnects, the Hyper-V enhanced session stops delivering input. UI tests then fail with
InjectMouseInput ... Access is deniedand "Test window lost focus". Use-MoveSessionToConsole, which runstscon <id> /dest:consoleas SYSTEM inside the VM, so the VM desktop stays interactive. Reconnecting with vmconnect moves the session back. - Instrumenting is slow: about 20-50 min and about 3 GB RAM for chk MUXC. Don't interrupt it; later runs reuse the cache. Use
-ForceReinstrumentafter a rebuild if the hash didn't change but you want a new session id. - Stale build: if
BuildOutputcomes from another branch or an older commit, the payload may not contain the component's tests. The test check before Step 1 catches this; without it, TAEF reports "The selection criteria did not match any tests" on the VM and Step 3 fails after the long instrumentation. - Incremental deploy manifest:
tools\run-tests-on-vm.ps1only copies files whose size or timestamp changed since its last deploy (TestPayload\.deploy-manifest-<VM>-<flavor>.json). Step 4 restores the VM behind its back, andstatic_covrun*.dllalways keep the tool's timestamp, so Step 3 removes the instrumented files from that manifest before every run. Without that, a rerun silently tests the original DLL (empty coverage), or the instrumented DLL is deployed withoutstatic_covrun64.dlland the test app crashes with "ClassFactory cannot supply requested class". - Session id must match: the DLL the test process loads must carry the collector's session id. If the coverage file is tiny or empty, check
work\raw\<run>\collector.logand confirm the app-local copy (MUXControlsTestApp\Microsoft.UI.Xaml.Controls.dll) is the instrumented one. - Rebuilds overwrite the instrumented copy: rebuilding
MUXControlsTestAppre-stages an older Controls DLL intoBuildOutput\...\UnpackagedApps\MUXControlsTestApp. That doesn't matter here because Step 2 overwrites the payload copies, but don't runrun-tests-on-vm.ps1without-SkipPayloadin between, because that recreates the payload. - Expected failures still count toward coverage: failing or ignored tests still execute product code until they fail, and Ignored tests don't run at all.
- Known crash at exit is harmless: TitleBar runs fail-fast at app exit, which shows as cleanup errors. Coverage still flushes because the collector is out of process.
- Numbers differ from CI: a local VM run uses a different OS build, flavor (x64 vs CI's x86) and test subset. Compare per file, not the module total.
- NULL DACL: the collector pipe is open to every local user until shutdown, so that low-integrity test processes can connect (otherwise coverage is empty with ACCESS_DENIED). That's fine on a dedicated test VM, but avoid it on shared machines; the agent workflow tells the user before every run.
cmd /cquoting: starting the collector viacmd /c "<exe>" ... > "<log>"silently fails, because cmd strips the outer quotes. Step 3 therefore writes a.cmdwrapper. If the collector pipe never appears, check that wrapper andC:\WinUICoverage\out\collector-<run>.logon the VM.- Same tool for instrument and collect: the collector must be the same
Microsoft.CodeCoverage.Console.exeversion that instrumented the DLL. Step 2 records the tool, and Step 3 stages that exact version toC:\WinUICoverage\CoverageTool\<version>. If that tool is gone or changed version (for example after a VS update), Step 2 re-instruments instead of reusing the cache. When several VS installs exist, the highest file version wins; path string order is not used. - Relink is not byte-deterministic: Step 1 therefore reuses its previous output while the recorded link inputs are unchanged. Otherwise the Step 2 cache, keyed by DLL hash, would miss and re-instrument for 45 minutes.
- Single-file bug in
lib\Get-FunctionCoverage.ps1: with a single.coverageinput, the script's own merge produces an empty<results/>. An if-expression unwraps the one-element array, so@inputFilessplats nothing. Step 5 works around this by pre-merging (dotnet-coverage merge -f xml) and calling the script with-SkipMerge, so the script itself is left as is. - Host suspends pause the run: a Cloud PC host that sleeps or suspends pauses instrumentation; it resumes and finishes afterwards. Keep the host awake for predictable timing.
Parameters (Invoke-WinUIVmCoverage.ps1)
| Parameter | Default | Notes |
-RepoRoot | required | WinUI checkout with a completed local build |
-VMName | required | Hyper-V VM |
-TestFilter | required | One or more filters passed to run-tests-on-vm.ps1, e.g. *.TitleBarTests.*. With several, Step 3 runs once per filter and Step 5 merges the .coverage files. |
-OutputDir | <RepoRoot>\BuildOutput\Coverage\<Flavor>\<ComponentName> | Work and report root (git-ignored by default) |
-ComponentName / -ComponentPathRegex | TitleBar | Regex on the source path selecting the component's files |
-Module | Microsoft.UI.Xaml.Controls.dll | or Microsoft.UI.Xaml.Controls.Tabular.dll (TableView and the tabular helpers), or Microsoft.ui.xaml.dll |
-Flavor | amd64chk | Build flavor; payload x64chk |
-BaselinePerFileCsv / -BaselineLabel / -BaselineRepoRoot | none | A corrected-per-file.csv from another coverage run to compare with, e.g. PerModule\<Module>\corrected-per-file.csv from an earlier run of this skill, or lib\Split-CoverageByModule.ps1 run over a CI build's merged Cobertura file |
-MoveSessionToConsole | off | Recommended on Cloud PC / RDP hosts |
-RefreshPayload | off | Run test\CreateTestPayload.ps1 first; stops if it fails |
-ForceReinstrument | off | Ignore the instrumented-DLL cache |
-SkipTestCheck | off | Skip listing the matching tests in the payload (same test files and selection as runtests) before instrumenting |
-SkipFunctionCoverage | off | Skip the function-level merge |
Files in this skill
| File | Purpose |
scripts\Invoke-WinUIVmCoverage.ps1 | One-command orchestrator for Steps 1-5. Step 3 runs once per -TestFilter. The payload and VM are restored in finally (and at the start of the next run if a run was killed). |
scripts\Step1-New-InstrumentableDll.ps1 | Relinks MUXC or Tabular with /DEBUGTYPE:CV,FIXUP from the recorded link command, outside BuildOutput. |
scripts\Step2-Instrument-Payload.ps1 | Static instrumentation (cached) and broadcast into TestPayload\<flavor>, with backups. |
scripts\Step3-Invoke-VmCoverageRun.ps1 | Starts the collector on the VM, runs the tests through tools\run-tests-on-vm.ps1 -SkipPayload, shuts the collector down and downloads the coverage file. |
scripts\Step4-Restore-Payload.ps1 | Restores the payload and the VM copies, hash-verified. |
scripts\Step5-Get-ComponentCoverage.ps1 | Merge, per-module dedup, component filter, baseline comparison, function coverage, HTML tree and coverage-summary.md. |
scripts\lib\Set-CoveragePipeAcl.ps1 | Puts a NULL DACL on the collector's named pipe so low-integrity TAEF test processes can connect. |
scripts\lib\Repair-CoverageDuplicates.ps1, Split-CoverageByModule.ps1 | Deduplicate merged Cobertura by (file, line), overall and per module, so the numbers match the Azure DevOps Code Coverage tab. |
scripts\lib\Get-FunctionCoverage.ps1 | Per-function coverage from the native XML merge. |
scripts\lib\Build-CoverageTreeReport.ps1, Build-FunctionCoverageTreeReport.ps1 | Single-file HTML folder/file (and function) tree reports. |
Shared repo tool used by Gate 1: tools\Set-VmCredential.ps1 validates the VM, takes the password in a separate window, writes the encrypted credential cache (only after every check passes), and checks the logon and the active desktop.
Trending
Quiet since August.about the whole repository
Who's talking about microsoft/microsoft-ui-xaml
- dotnet/maui“Cross platform UX for .NET 5”GitHub · Jul 18, 2017 · 217 reactions
- A Hacker News story“WinUI 3 Performance: A Leap Forward”Hacker News · May 14, 2026 · 121 points
- xamarin/Xamarin.Forms“Proposal: Simplify Grid Column and Row Definitions”GitHub · Aug 28, 2019 · 67 reactions
- dotnet/maui“[Enhancement] Cross platform media player”GitHub · Aug 27, 2021 · 44 reactions
- dotnet/maui“Support Global Exception Handling Mechanism for .NET MAUI”GitHub · Mar 23, 2022 · 41 reactions
The biggest 5 of 72 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 72
Talked about on GitHub, Stack Overflow, Hacker News and Bluesky (72 times).
On GitHub · 30
- Jul 18, 2017Cross platform UX for .NET 5 — dotnet/maui217 reactions · 31 comments
- Aug 28, 2019Proposal: Simplify Grid Column and Row Definitions — xamarin/Xamarin.Forms67 reactions · 13 comments
- Aug 27, 2021[Enhancement] Cross platform media player — dotnet/maui44 reactions · 23 comments
- Mar 23, 2022Support Global Exception Handling Mechanism for .NET MAUI — dotnet/maui41 reactions · 12 comments
- Apr 26, 2019Adds UWP support to Shell — xamarin/Xamarin.Forms39 reactions · 45 comments
25 more on GitHub
- Aug 28, 2019Proposal: Simplify Grid Column and Row Definitions — dotnet/wpf35 reactions · 7 comments
- Jun 22, 2019Support using Win2D with WinUI — microsoft/Win2D35 reactions · 28 comments
- May 19, 2020[WinUI3] Windows Community Toolkit 7.0.1 for Project Reunion 0.5 — CommunityToolkit/WindowsCommunityToolkit30 reactions · 49 comments
- Mar 18, 2020Proposal: Allow the App to Print without showing the Confirmation Dialog to user — microsoft/WindowsAppSDK28 reactions · 47 comments
- Oct 8, 2022Windows Unpackaged support in .NET MAUI — dotnet/maui27 reactions · 4 comments
- May 29, 2020Discussion: Decouple MSIX from AppContainer — microsoft/WindowsAppSDK26 reactions · 14 comments
- Aug 22, 2021BlazorWebView drag and drop does not work with MAUI Templates — dotnet/maui24 reactions · 96 comments
- Nov 14, 2019[Enhancement] WinUI Support — xamarin/Xamarin.Forms23 reactions · 11 comments
- Feb 7, 2025Fix issues with High CPU Usage on background — Devolutions/UniGetUI10 reactions
- Jun 20, 2022Remove Xaml from `windows` crate — microsoft/windows-rs8 reactions · 16 comments
- Dec 14, 2023XY focus — AvaloniaUI/Avalonia7 reactions · 10 comments
- Jun 1, 2019Porting ItemsRepeater from WinUI — AvaloniaUI/Avalonia7 reactions · 14 comments
- Feb 12, 2026Update to Windows App SDK 1.8 — microsoft/Win2D5 reactions · 1 comment
- Jan 30, 2025Improve VisualState order and prevent sticky Focused visual state — dotnet/maui5 reactions · 84 comments
- Dec 27, 2023Add BackgroundSizing — AvaloniaUI/Avalonia5 reactions · 16 comments
- Mar 21, 2022Add new ColorSpectrum Primitive — AvaloniaUI/Avalonia5 reactions · 30 comments
- Mar 19, 2025[Windows] Upgrade to Windows App SDK 1.7 — dotnet/maui4 reactions · 32 comments
- Nov 17, 2023Create a "Similar Issues" bot — dotnet/maui4 reactions
- Dec 17, 2021Do not copy UWP behavior with ListBoxItem horizontal alignment — AvaloniaUI/Avalonia4 reactions · 3 comments
- Nov 29, 2021Make DispatcherQueueSynchronizationContext faster and zero-alloc — microsoft/CsWinRT4 reactions · 7 comments
- Sep 15, 2021Update to MUX 2.7 — microsoft/terminal4 reactions · 3 comments
- Aug 11, 2020Add support for WinUI 3 — mono/SkiaSharp4 reactions · 18 comments
- Dec 3, 2025New functionalities of Storage.Pickers: SettingsIdentifier; InitialFileTypeIndex; Title; PickMultipleFoldersAsync; ShowOverwritePrompt; — microsoft/WindowsAppSDK3 reactions · 11 comments
- Mar 15, 2025Add BreadcrumbBar — amwx/FluentAvalonia3 reactions · 1 comment
- Sep 9, 2023[Keyboard Manager] Modernize the editor UI — microsoft/PowerToys3 reactions · 36 comments
On Stack Overflow · 30
- Dec 10, 2021Where is the designer view in WinUI 3?17 votes
- Sep 4, 2019Layout cycle detected. Layout could not complete. Layout cycle detected. Layout could not complete6 votes
- Nov 11, 2020NavigationView Pane background5 votes
- Jun 16, 2023c# WebView2 user directory "Access Denied"4 votes
- Feb 13, 2023Remove ListViewItemPresenter border in Microsoft.UI.Xaml ListView3 votes
25 more on Stack Overflow
- Nov 12, 2020What is the <ColumnDefinition /> used for in Xamarin Forms and can it be replaced with a value setting?3 votes
- Apr 22, 2020Is it possible to stop the first Entry getting Focus in a ScrollView in Xamarin Forms3 votes
- Sep 21, 2018UWP NavigationView is not supported3 votes
- Aug 4, 2025Difference between Windows App SDK and WinUI 32 votes
- Nov 13, 2024How to fix MAUI application crash with "Layout cycle detected. Layout could not complete." exception when data is loaded into views beyond a limit2 votes · 1 answer
- Jan 24, 2024How can I build a self-contained C# WinUI application from within a Windows Docker container (`XamlCompiler.exe` exits with code `-1073741515`)?2 votes
- Sep 29, 2023MAUI Picker style in Windows Platforms2 votes
- Sep 3, 2023UWP XAML NavigationView - CornerRadius on Content Panel2 votes
- Apr 25, 2023WinUI 3 Circle Button needs to keep hover animation2 votes
- Sep 4, 2021How to Access WinUI Generic.xaml file?2 votes
- Nov 29, 2019How to automatically scroll ScrollViewer - only if the user did not change scroll position2 votes
- Apr 12, 2024Cannot create a new WinUI 3 app and target .NET 81 vote · 1 answer
- Apr 11, 2024Make window only as large as required1 vote
- Mar 27, 2024What the equivalent to LocalPrintServer and PrintQueue that can be used in WinUI1 vote
- Mar 8, 2024SwapChainPanel DPI Awareness1 vote
- Jun 12, 2023Change Microsoft.UI.Xaml.Controls.Expander Title property when expanded1 vote · 1 answer
- May 1, 2023WinUI 3/WASDK 1.3 How do I shorten the width of the month on a DatePicker control?1 vote · 1 answer
- Nov 24, 2022Camera Video streaming control (CaptureElement) not available for Winui3 c#1 vote
- Nov 9, 2022Winui3 Navigationview PanetoggleButton increase size1 vote
- Mar 13, 2022WinUI 3 ItemsRepeater re-orders/removes items when scrolling within a ScrollViewer and using UniformGridLayout1 vote · 1 answer
- Jan 23, 2022Using TabItemTemplateSelector in WinUI 3 in conjunction with a TemplateSelector resulting in weirdly nested controls1 vote
- Feb 3, 2021Binding a Static Generic Class in XAML1 vote
- Oct 25, 2020UWP CommandBar moves vertically when IsOpen changes1 vote · 1 answer
- Jul 4, 2020Unable to change the background colour of TeachingTip in UWP1 vote
- Jul 16, 2019Creating a Subclass of Page in UWP1 vote · 2 answers
On Hacker News · 11
- May 14, 2026WinUI 3 Performance: A Leap Forward121 points · 141 comments
- Oct 25, 2023WinUI3 Source Available4 points
- Feb 13, 2022Dependency property is much slower in WinUI 3 than in WPF4 points
- Jul 1, 2019Windows UI Library Roadmap4 points
- Oct 25, 2023WinUI 3 is now open source3 points
6 more on Hacker News
- Aug 29, 2026WinUI development is now happening on GitHub2 points
- May 26, 2024Is WinUI 3 Dead?2 points
- Nov 13, 2019Windows UI Library Roadmap Update2 points
- Nov 6, 2019First WinUI 3.0 Alpha now available2 points
- Aug 2, 2025WinUI OSS Update: Phased Rollout Toward Open Collaboration1 point
- Jul 23, 2024Windows UI Library1 point
On Bluesky · 1
- Jan 26, 2025Over here: github.com/microsoft/mi... — @dotmorten.xaml.dev1 likes and repost · 1 reply
In this repository7 other files it gives its agents.
- Samples/TableViewSampleApp/AGENTS.mdAGENTS.md
- src/.github/copilot-instructions.mdCopilot instructions
- buildSkill
- code-reviewSkill
- test-on-vmSkill
- bt-buildSkill
- test-suite-setupSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

