Skip to content

Test coverage + GitHub Actions CI (x64 & ARM64), fix blank hostname error#132

Merged
scottlerch merged 2 commits into
masterfrom
claude/test-coverage-ci-setup-607121
Jul 14, 2026
Merged

Test coverage + GitHub Actions CI (x64 & ARM64), fix blank hostname error#132
scottlerch merged 2 commits into
masterfrom
claude/test-coverage-ci-setup-607121

Conversation

@scottlerch

Copy link
Copy Markdown
Owner

Summary

Raises unit-test coverage for the shared core and headless CLI, adds a GitHub Actions CI workflow that gates PRs on both x64 and ARM64, and fixes a latent resource bug found along the way.

Coverage (HostsFileEditor.Core)

before after
Line 75.0% 87.8%
Branch 72.5% 83.9%
Method 74.6% 94.5%

192 → 286 Core tests. Highlights: HostsCli 51.6% → 98.8%, HostsFile 70% → 92%, HostsEntry 78% → 95%, HostsEntryList → 100%, and several classes to 100%.

The enabling piece is TestAssemblyInit: an [AssemblyInitialize] binds the HostsFile.Instance singleton to a temp file via the sanctioned HFE_HOSTS_PATH override before anything touches it, so the full apply/enable/disable/import/merge flow (and Run's catch branches, via a throwing IPrivilegedFileOperations) is exercised without ever touching the real hosts file.

The uncovered remainder is deliberate — all side-effectful and unsafe/impractical to unit-test: the runas UAC escalation helper, native comdlg32 file dialogs, the process-spawning file opener, ShowFirstInstance (kills the process), and the one-time legacy-archive migration.

UI tests

New HostsFileEditor.WinForm.Tests covers the classic edition's HostsFilter (delegates the three filter rules to Core's canonical MatchesFilter). A WinUI unit-test project was attempted for SelectionStateService but dropped — the WinAppSDK testhost won't launch (self-contained testhost, missing hostpolicy.dll); the modern edition is covered by its compile gate, and shared logic already lives in Core.

CI — .github/workflows/ci.yml

Runs on every PR and on pushes to master. Matrix over x64 (windows-latest) and ARM64 (windows-11-arm): builds Core/CLI/Elevate/WinForm + WinUI (-p:Platform=<arch>), runs the full test suite with OpenCover coverage, posts a coverage summary to the job summary, and uploads results. WinForm UI tests run on the x64 leg only (the project pins RID win-x64).

Bug fix — closes #131

Resources.InvalidHostnames (Core) had no matching key in Resources.resx, so the strongly-typed getter resolved to null — an invalid hostname surfaced a blank IDataErrorInfo message in both editions. Added the key ("Invalid host names", matching the WinForm value) plus regression coverage.

Test plan

  • dotnet test HostsFileEditor.Core.Tests — 286 passing (Release)
  • dotnet test HostsFileEditor.WinForm.Tests — 5 passing (Release)
  • Release builds of Core, Cli, Elevate, WinForm, WinUI (x64) succeed with 0 warnings (TreatWarningsAsErrors)
  • CI green on both x64 and ARM64 (validated from this draft PR)

🤖 Generated with Claude Code

…stname error

Raise HostsFileEditor.Core coverage from ~75% to ~88% line / ~84% branch /
~95% method by driving the previously-untested code paths:

- Exercise the headless CLI (HostsCli.Run) end-to-end — list/apply/enable/
  disable/import/merge plus the top-level catch branches — against the
  HostsFile.Instance singleton, bound to a temp file via the sanctioned
  HFE_HOSTS_PATH override in an [AssemblyInitialize] (TestAssemblyInit) so no
  test ever touches the real hosts file.
- Cover the small classes (exceptions, PrivilegedFileOperations helper
  selection, FileOpener registered-app resolution, NativeMethods, Resources,
  ConsoleAttach early-return) and the remaining HostsFile / HostsEntry /
  HostsEntryList / HostsArchive branches.
- The uncovered remainder is deliberately left: the runas UAC escalation,
  native comdlg32 dialogs, process spawn/kill, and the one-time archive
  migration — all side-effectful and unsafe to unit-test.

Add HostsFileEditor.WinForm.Tests covering the classic edition's HostsFilter
(the modern edition's logic is covered by its build gate; a WinUI unit-test
project was infeasible — the WinAppSDK testhost won't launch).

Add .github/workflows/ci.yml gating every PR (and pushes to master) on a
build + full test run across x64 (windows-latest) and ARM64 (windows-11-arm).

Fix #131: add the missing InvalidHostnames key to Core's Resources.resx so an
invalid hostname surfaces a real IDataErrorInfo message instead of a blank one
(the strongly-typed getter previously resolved to null).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rdening

- Fix cross-test flakiness: HostsEntry.Ping() is fire-and-forget and mutates the
  process-global ping counter / PingActivityChanged on a thread-pool
  continuation. Ping-starting test classes now drain in-flight pings in cleanup
  so they can't leak into (and flake) the ping-activity assertions here or in
  the pre-existing PingActivity_RaisesOnZeroBoundaryOnly.
- CI: pass an explicit RuntimeIdentifier (win-arm64 on the arm64 leg) to the
  WinForm/WinUI builds — both projects default RID to win-x64 regardless of
  Platform, so the arm64 leg was silently building x64 and never validating arm64.
- ConsoleAttach test: snapshot/restore Console.Out/Error so the rare
  attach-and-rebind path can't corrupt another test's output capture.
- Elevation-helper stub test: defensively clear a leftover stub so the
  no-helper case is order-independent.
- Replace a tautological HostsFilter test (compared the method to its own body)
  with concrete expected values that actually catch a wiring bug.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@scottlerch
scottlerch marked this pull request as ready for review July 14, 2026 20:10
@scottlerch
scottlerch merged commit 00fcddf into master Jul 14, 2026
2 checks passed
scottlerch added a commit that referenced this pull request Jul 14, 2026
)

The strongly-typed Resources.InvalidHostnames getter existed but Core's
Resources.resx had no matching <data name="InvalidHostnames"> entry, so it
resolved to null. HostsEntry.ValidateHostnames does
`SetError(nameof(HostNames), !_hostnamesValid ? Resources.InvalidHostnames : null)`
and SetError treats null as "clear the error", so an invalid hostname surfaced a
BLANK IDataErrorInfo message in both the classic and modern editions instead of
"Invalid host names".

Add the key ("Invalid host names", matching the WinForm resource) plus a
regression test asserting the invalid-hostname error message is the non-empty
resource string. Split out of the larger CI/coverage PR #132 so the user-facing
fix can land on its own.

Closes #131

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.

InvalidHostnames validation message is blank (missing resource key)

1 participant