ANcpLua.Roslyn.Utilities.Testing 1.56.1

dotnet add package ANcpLua.Roslyn.Utilities.Testing --version 1.56.1
                    
NuGet\Install-Package ANcpLua.Roslyn.Utilities.Testing -Version 1.56.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ANcpLua.Roslyn.Utilities.Testing" Version="1.56.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ANcpLua.Roslyn.Utilities.Testing" Version="1.56.1" />
                    
Directory.Packages.props
<PackageReference Include="ANcpLua.Roslyn.Utilities.Testing" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ANcpLua.Roslyn.Utilities.Testing --version 1.56.1
                    
#r "nuget: ANcpLua.Roslyn.Utilities.Testing, 1.56.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ANcpLua.Roslyn.Utilities.Testing@1.56.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ANcpLua.Roslyn.Utilities.Testing&version=1.56.1
                    
Install as a Cake Addin
#tool nuget:?package=ANcpLua.Roslyn.Utilities.Testing&version=1.56.1
                    
Install as a Cake Tool

NuGet .NET Standard 2.0 License: MIT

ANcpLua.Roslyn.Utilities

A focused utility library for writing Roslyn source generators, analyzers, and code-fix providers. The shape is opinionated: the types here are the ones that make an incremental generator actually cache, a symbol comparison actually readable, and a code emission actually deterministic.

Agent test doubles, MAF conformance suites, and workflow fixtures live in the sibling ANcpLua.Agents package. This repo focuses on Roslyn/MSBuild/OTel-for-analyzer-authors.

The library is the author's own. Use it, improve it (the upstream is this repo), or propose switching directions — don't reinvent locally.

Packages

Package Target What it's for
ANcpLua.Roslyn.Utilities netstandard2.0 Runtime + Roslyn utilities as a normal NuGet reference
ANcpLua.Roslyn.Utilities.Sources source-only Embeds the utilities as internal source into source generators (generators can't load NuGet DLLs at runtime)
ANcpLua.Roslyn.Utilities.Polyfills source-only init, required, Index/Range, nullable & trim attributes for netstandard2.0
ANcpLua.Roslyn.Utilities.Testing net10.0 Generator/analyzer/codefix test infrastructure, MSBuild/NuGet integration tests, cross-framework web testing (xUnit/NUnit/TUnit/Bunit), OTel instrumentation helpers, BitNetFixture live-LLM integration
ANcpLua.Roslyn.Utilities.Testing.Aot netstandard2.0 AOT/trim test attributes ([AotTest], [TrimTest], [AotSafe], [TrimSafe]), TrimAssert, FeatureSwitches, MSBuild orchestration for standalone AOT verification

Quickstart — writing a source generator

dotnet add package ANcpLua.Roslyn.Utilities.Sources

A canonical incremental generator is ~25 lines when the utilities do their job — see src/ANcpLua.AotReflection/AotReflectionGenerator.cs in this repo for the reference shape:

[Generator]
public sealed class MyGenerator : IIncrementalGenerator
{
    public void Initialize(IncrementalGeneratorInitializationContext context)
    {
        var flows = context.SyntaxProvider.ForAttributeWithMetadataName(
            "MyNamespace.TracedAttribute",
            static (node, _) => node is ClassDeclarationSyntax,
            static (ctx, ct) => TypeExtractor.Extract(ctx, ct));

        var types = flows.ReportAndStop(context);

        var files = types
            .Select(static (m, _) => OutputGenerator.Generate(m))
            .CollectAsEquatableArray();

        files.AddSources(context);
    }
}

What the library provides at each step:

  • ForAttributeWithMetadataName — filter syntax before expensive semantic work (Roslyn built-in; the library wraps for ergonomics)
  • DiagnosticFlow<T> — railway-oriented pipeline carrying value + accumulated diagnostics, value-equatable for incremental caching
  • ReportAndStop — drain the flow into ReportDiagnostic and yield values
  • CollectAsEquatableArray / ToEquatableArray / ToEquatableArrayOrDefault — value-equatable collections so the generator cache actually hits
  • AddSources — emit FileWithName records without boilerplate
  • Match.Type() / Match.Method() — fluent symbol matching, no string comparisons
  • IndentedStringBuilderBeginBlock()/EndBlock() scopes, no hardcoded indentation strings
  • GeneratedCodeHelpers<auto-generated/> headers, #nullable enable, pragma helpers

Testing an agent or a MAF workflow

Agent test doubles (FakeChatClient, FakeReplayAgent, ActivityCollector), the provider-agnostic MAF conformance suite (RunTests, RunStreamingTests, ChatClientAgentRunTests, StructuredOutputRunTests), reference fixtures for OpenAI / Azure / Anthropic / Ollama / Gemini / OpenRouter, and the WorkflowFixture<TInput> harness ship in the sibling ANcpLua.Agents package.

What's in the box

Incremental pipeline (generator authors)

  • DiagnosticFlow<T> + DiagnosticFlowReportingExtensions — railway-oriented flow with value + accumulated DiagnosticInfo
  • IncrementalValuesProviderExtensionsReportAndStop, CollectAsEquatableArray, AddSources, and other pipeline verbs
  • SyntaxValueProviderExtensions — ergonomic ForAttributeWithMetadataName wrappers
  • SourceProductionContextExtensions — context helpers
  • EquatableArray<T> + EquatableArrayExtensions (.ToEquatableArray, .ToEquatableArrayOrDefault, .AsEquatableArray) — value equality so the cache actually hits
  • FileWithName — record for emitted-file payload
  • DiagnosticInfo + LocationInfo + EquatableMessageArgs — value-equatable diagnostic carriers
  • ResultWithDiagnostics<T> — result payload paired with diagnostics, for pipelines where the value survives errors

Symbol analysis & matching

  • Match fluent DSLMatch.Type() / Match.Method() / Match.Property() / Match.Field() / Match.Parameter() with the per-kind matchers under Matching/ (MethodMatcher, TypeMatcher, etc.)
  • Invoke / InvocationMatcher — invocation-shape matching
  • SymbolExtensions, TypeSymbolExtensions, MethodSymbolExtensions, NamespaceExtensionsIsEqualTo, ImplementsInterface, GetAllBaseTypesAndSelf, and the usual suspects
  • AttributeExtensionsGetAttribute, HasAttribute, TryGetAttribute with constructor-arg accessors
  • InvocationExtensions / OperationExtensions / OperationHelperIInvocationOperation analysis helpers
  • SemanticGuard<T> + SemanticGuard — chain semantic predicates with early-exit
  • SemanticModelExtensions / CompilationExtensions / SyntaxExtensions

Code emission

  • IndentedStringBuilder + IndentScopeBeginBlock()/EndBlock() scopes, no hardcoded indentation
  • GeneratedCodeHelpers<auto-generated/> header, nullable/pragma directives
  • ValueStringBuilder — stack-allocated StringBuilder for hot paths
  • SyntaxBuilders (Analyzers/) — fluent builders for common code-fix patterns (ExtensionCall, StaticCall, NameOf)

Analyzer authoring

  • DiagnosticAnalyzerBase — convention base class
  • DiagnosticCategories / DiagnosticSeverities — category/severity constants
  • DeprecatedOtelAttributes — 50+ attribute-name mappings synced to OTel GenAI semconv 1.40 (catches gen_ai.system and friends during analysis)
  • IncrementalPipelineHelpers — pipeline wiring utilities
  • MappingRegistry / TypeCache<TEnum> — cached lookups for analyzer hot paths

Async & time

  • AsyncSequenceExtensions — LINQ-ish operators over IAsyncEnumerable<T>
  • ParallelAsyncExtensions — channel-based parallel enumeration with ordering control
  • ExpiringCache<TKey,TValue> — TTL cache for analyzer results
  • TimeConversions — OTel nanosecond helpers

Dictionary & collection ergonomics

  • DictionaryExtensionsGetOrInsert(key, context, factory) (closure-free, hot-path), GetOrAdd(key) / GetOrAdd(key, factory) (ergonomic), MapIfAbsent(src, dst, transform) (cross-key copy for vendor-adapter telemetry mappers)
  • EnumerableExtensions — dedup, partition, chunking, MinBy/MaxBy
  • ListExtensions — in-place mutation helpers

Guards & null handling

  • Guard — null / range / path / type guards
  • NullableExtensionsMap-style combinators for T?
  • TryExtensionsTryParseX, dictionary GetOrNull / GetOrDefault / GetOrElse

Models & OTel enums

  • SpanKind, SpanStatusCode — OTel enums
  • PagedResult<T> — standard paginated response shape

Polyfills

Language and API backports for netstandard2.0 consumers (via the separate .Polyfills package):

Polyfill Enables Opt-out
Index / Range array[^1], array[1..3] InjectIndexRangeOnLegacy=false
IsExternalInit record types, init setters InjectIsExternalInitOnLegacy=false
Nullable attributes [NotNull], [MaybeNull], [MemberNotNull], [NotNullWhen] InjectNullabilityAttributesOnLegacy=false
Trim/AOT attributes [RequiresUnreferencedCode], [DynamicallyAccessedMembers] InjectTrimAttributesOnLegacy=false
TimeProvider Testable time abstraction InjectTimeProviderPolyfill=false
Lock System.Threading.Lock InjectLockPolyfill=false
required, params collections, CallerArgumentExpression, UnreachableException, StackTraceHidden, ExperimentalAttribute C# 11–13 language features on ns2.0 per-feature MSBuild props

Disable all at once: <InjectAllPolyfillsOnLegacy>false</InjectAllPolyfillsOnLegacy>

Testing — what ships in .Testing

Generator, analyzer, codefix, refactoring, MSBuild integration, and cross-framework web testing.

  • Generator tests: Test<TGenerator> (fluent entry), GeneratorTestHelper.RunGenerator<TGenerator>() (assertion-oriented one-liners), GeneratorCachingReport (compares two runs, detects cache hits), Compile / CompileResult (dynamic compilation with Shouldly-style assertions)
  • Analyzer / CodeFix / Refactoring tests: AnalyzerTest<TAnalyzer>, CodeFixTest<TAnalyzer,TCodeFix>, CodeFixTestWithEditorConfig<TAnalyzer,TCodeFix>, RefactoringTest<TRefactoring>, SolutionRefactoringTest<TRefactoring>, LogAssert
  • MSBuild integration tests: ProjectBuilder, PackageProjectBuilder, PackageTestBase<TFixture> / NuGetPackageTestBase, NuGetPackageFixture, BuildResult + BuildResultAssertions, SarifFile parsers, DotNetSdkHelpers / NetSdkVersion, MSBuildConstants
  • Web testing — one base per framework:
    • xUnit (root): IntegrationTestBase<TProgram>, KestrelTestBase<TProgram>
    • WebTesting/NUnit/, WebTesting/TUnit/, WebTesting/Bunit/ — per-framework equivalents
    • Plus FakeLoggerExtensions for structured log capture
  • OTel instrumentation: ActivityInstrumentation, MetricsInstrumentation, LoggingConventions, LogEnricherInfrastructure, DataClassificationHelpers (PII/Secret redaction)
  • Live-LLM integration: BitNetFixture, BitNetAttribute, BitNetTestGroup — xUnit v3 collection fixture for llama.cpp BitNet server

AOT testing — what ships in .Testing.Aot

Separate package (netstandard2.0, zero runtime deps). Attributes + MSBuild props for verifying AOT/trim behavior.

  • [AotTest], [AotSafe], [AotUnsafe] — mark methods as AOT-verified or AOT-excluded
  • [TrimTest], [TrimSafe], [TrimUnsafe] — same for IL trimming; TrimMode enum selects Partial / Full
  • TrimAssert.TypePreserved(...) / TypeRemoved(...) — runtime assertions against the trimmed binary
  • FeatureSwitches — constants for common AOT feature switches (e.g. JsonReflection)
  • AotRuntime — runtime AOT/trim detection
  • MSBuild orchestration (build/*.props + *.targets + ProjectTemplate.csproj.txt) ships inside the package itself; no external SDK dependency

Separate: AOT reflection generator

This repo also ships ANcpLua.Analyzers.AotReflection — an incremental source generator that replaces runtime typeof(T).GetProperties() with compile-time metadata, making types NativeAOT- and trim-safe. Mark a type [AotReflection] and a generated FooMetadata class appears with strongly-typed getter/setter/invoker delegates. Pair with ANcpLua.Roslyn.Utilities.Testing.Aot to verify the output survives PublishAot=true and PublishTrimmed=true.

Design principles

  • Compile-time over runtime reflection. EquatableArray<T> for generator caching, DiagnosticFlow<T> for pipeline error accumulation, IndentedStringBuilder for emission — the shape of an incremental generator the compiler cache actually likes.
  • Allocation-conscious in analyzer hot paths. ValueStringBuilder for stack-allocated string building, Boxes for cached boxed primitives, closure-free GetOrInsert<TContext> for dictionary inserts.
  • OTel semconv 1.40 native. DeprecatedOtelAttributes catches gen_ai.system and 50+ other deprecated attribute names during analysis.
  • Test discipline. GeneratorCachingReport over hand-rolled cache assertions. Test<TGenerator> fluent runner over hand-rolled CSharpGeneratorDriver plumbing. The shipped-internally ForbiddenTypeAnalyzer catches ISymbol/Compilation snuck into pipeline models. Agent-specific test doubles live in the sibling ANcpLua.Agents package.
  • Source-only delivery for generators. The .Sources package rewrites the utilities to internal via a pack-time PowerShell transform (Transform-Sources.ps1), because source generators can't load NuGet DLLs at runtime.

Documentation

ancplua.mintlify.app/utilities — full API reference with examples.

  • ANcpLua.NET.Sdk — opinionated .NET SDK wrapper built on the same conventions
  • ANcpLua.Analyzers — the author's analyzer catalogue, built on these utilities
  • ANcpLua.Agents — agent test doubles, MAF conformance, workflow fixtures

License

MIT © Alexander Nachtmann

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.56.1 0 4/21/2026
1.56.0 0 4/21/2026
1.55.0 0 4/21/2026
1.54.1 0 4/20/2026
1.54.0 0 4/20/2026
1.53.3 54 4/20/2026
1.53.2 32 4/19/2026
1.53.1 34 4/19/2026
1.53.0 229 4/18/2026
1.52.1 38 4/18/2026
1.52.0 159 4/15/2026
1.51.1 146 4/12/2026
1.51.0 251 4/3/2026
1.50.0 98 4/3/2026
1.49.0 98 4/2/2026
1.48.0 209 3/20/2026
1.47.0 205 3/12/2026
1.45.0 378 3/10/2026
1.43.0 250 2/28/2026
1.42.0 226 2/28/2026
Loading failed