Skip to content

test(aot): smoke-check every public member under Native AOT, and guard it - #392

Merged
Chris-Wolfgang merged 2 commits into
mainfrom
test/aot-smoke-full-surface
Sep 27, 2026
Merged

Chris-Wolfgang merged 2 commits into
mainfrom
test/aot-smoke-full-surface

Conversation

@Chris-Wolfgang

Copy link
Copy Markdown
Owner

Summary

The Native AOT smoke app (tests/Wolfgang.TryPattern.AotSmoke, run by aot-smoke.yaml on linux-x64) called each public method once, mostly on the success path. It now runs 46 checks, each naming the PublicAPI member it covers (Check("Result.Flatten", …)). Failures are listed by member.

What's now covered under AOT that wasn't:

Area Why it matters under AOT
Value-type and reference-type instantiations of every generic member (Run<T>, RunAsync<T>, Result<T>.*), including a user-defined record struct AOT compiles value-type generics separately; reference types share code. Previously Run<T> only ran with int and RunAsync<T> only with string.
Exception paths: argument guards, failures, a pre-canceled token on both RunAsync overloads, Value on a failed Result<T> These paths pull in exception-handling and stack-trace machinery that trimming can remove.
Whitespace-message fallback (ErrorMessage becomes the exception type name) It reads ex.GetType().Name, the one place the library touches type metadata.
The protected Result(bool, string?) constructor, through a subclass It's in PublicAPI but was never called.
Combinator edge paths: empty and null input, false results, a multi-failure Flatten joining its messages These cover every branch of the combinators.

Drift guard: the new AotSmokeCoverageTests (unit suite, net8.0+) reads every src/Wolfgang.TryPattern/**/PublicAPI.*.txt, derives the member keys, and fails naming any public member with no Check in the smoke app. So a new public method can't ship without an AOT smoke check. It uses plain string parsing rather than [GeneratedRegex]: the generated code counted against the 100% test-assembly coverage gate (it measured 94.3% with regexes).

Verification

  • Smoke app build: trim and AOT analyzers on, warnings as errors: 0 warnings, 0 errors. The regular .NET runtime (JIT) run gave OK: 46 AOT smoke checks passed.
  • Local Native AOT publish (win-x64): the IL compiler ran with no IL2xxx/IL3xxx warnings, but linking needs the C++ build tools, which aren't installed here. The native build and run are verified by aot-smoke.yaml on this PR (linux-x64); its path filter includes tests/Wolfgang.TryPattern.AotSmoke/**.
  • Drift guard: passes as-is. With every "Try.RunAsync<T>" check renamed it fails with Actual: ["Try.RunAsync<T>"]; with "Result.AnyFailed" renamed it fails with ["Result.AnyFailed"].
  • Unit tests: pass on net48 and net5.0–net10.0. Wolfgang.TryPattern.Tests.Unit is at 100% line coverage on the merged frameworks.
  • Local InspectCode: no findings in the changed files. The only 7 findings are the existing ConcurrencyStressTests ones fixed by test(concurrency): clear the seven InspectCode alerts in ConcurrencyStressTests #391.

This is test-only, with nothing in src/, so no changelog fragment.

🤖 Generated with Claude Code

Chris-Wolfgang and others added 2 commits September 27, 2026 13:38
…d it

The AotSmoke app called each public method once, mostly on the happy path.
It now runs 46 checks, each naming the PublicAPI member it covers:

- both value-type and reference-type (plus a user-defined struct)
  instantiations of every generic member, since AOT compiles value-type
  generics separately;
- the exception paths: argument guards, failures, a pre-canceled token on
  both RunAsync overloads, Value on a failed Result<T>;
- the whitespace-message fallback, which reads ex.GetType().Name, the one
  place the library touches type metadata;
- the protected Result(bool, string?) constructor, through a subclass;
- the combinators' empty, null, false and multi-failure paths.

AotSmokeCoverageTests (unit suite, net8.0+) reads every PublicAPI.*.txt,
derives the member keys, and fails naming any member with no Check in the
smoke app, so new public API cannot ship without an AOT smoke check.
String parsing rather than [GeneratedRegex]: generated code would count
against the 100% test-assembly coverage gate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Chris-Wolfgang
Chris-Wolfgang merged commit 4363fb5 into main Sep 27, 2026
26 checks passed
@Chris-Wolfgang
Chris-Wolfgang deleted the test/aot-smoke-full-surface branch September 27, 2026 18:34
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.

1 participant