Add generator groundwork and document generated-test settings#163
Merged
cwinland merged 6 commits intoMay 6, 2026
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR lays the first end-to-end groundwork for FastMoq’s explicit generated-harness path by introducing a new source generator project, adding runtime constructor-planning/graph metadata APIs the generator can target, and documenting the emerging generated-test settings + targeting contract.
Changes:
- Add
FastMoq.Generatorswith an incremental generator that emitsMockerTestBase<T>constructor-signature metadata for explicit[FastMoqGeneratedTestTarget]partial harnesses. - Add public constructor-planning models (
InstanceConstructionRequest/InstanceConstructionPlan) plus internal graph/bootstrap descriptor plumbing to support runtime + generated harness parity. - Introduce/expand analyzer-side package-layout + target-shape matrix support and document the generated-test settings direction (
#162), plus add benchmark evidence for the generated harness setup path.
Reviewed changes
Copilot reviewed 38 out of 38 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| FastMoq/packages.lock.json | Locks updated transitive dependencies (incl. EFCore patch, Castle.Core, DurableTask-related deps). |
| FastMoq/FastMoq.csproj | Packs generator artifacts and references FastMoq.Generators as an analyzer-style asset. |
| FastMoq.Tests/MockerTestBaseConstructionPlanTests.cs | Adds tests for MockerTestBase<T> construction-plan + bootstrap descriptor behavior. |
| FastMoq.Tests/InternalSampleServiceTests.cs | Removes FluentAssertions using in favor of the repo’s assertion setup. |
| FastMoq.Tests/InstanceConstructionPlanTests.cs | Adds tests for Mocker.CreateConstructionPlan(...) parameter-source and selection outcomes. |
| FastMoq.Tests/InstanceConstructionGraphTests.cs | Adds tests for construction graph projection and harness hook mapping. |
| FastMoq.Tests/GlobalUsings.cs | Switches test assertions to AwesomeAssertions global usings. |
| FastMoq.Tests/FastMoq.Tests.csproj | Updates test dependencies to use AwesomeAssertions (drops FluentAssertions). |
| FastMoq.Tests.Web/GlobalUsings.cs | Switches web test project global usings to AwesomeAssertions. |
| FastMoq.sln | Adds the new FastMoq.Generators project to the main solution. |
| FastMoq.Generators/GeneratedHarnessSourceGenerator.cs | New incremental generator emitting constructor-signature metadata for explicit harness targets. |
| FastMoq.Generators/FastMoq.Generators.csproj | New generator project configuration + packing under analyzers/dotnet/cs. |
| FastMoq.Core/Models/InstanceConstructionRequest.cs | New public request model for constructor-selection intent. |
| FastMoq.Core/Models/InstanceConstructionPlan.cs | New public resolved plan model + parameter plan + parameter-source enum. |
| FastMoq.Core/Models/InstanceConstructionGraph.cs | Internal graph model projecting plan + ordered dependency nodes/edges. |
| FastMoq.Core/Models/ComponentHarnessBootstrapDescriptor.cs | Internal descriptor for harness bootstrap knobs + graph projection. |
| FastMoq.Core/MockerTestBase_Constructors.cs | Adds component construction request/plan helpers + graph/bootstrap descriptor projection. |
| FastMoq.Core/Mocker.cs | Renames internal constructor-selection request struct to avoid collision with new public API model. |
| FastMoq.Core/Mocker.ConstructionPlan.cs | Implements CreateConstructionPlan(...), internal graph creation, and request-mapping helpers. |
| FastMoq.Core/KnownTypeRegistry.cs | Adds query helpers to detect known-type / managed-instance resolution for planning decisions. |
| FastMoq.Benchmarks/GeneratedHarnessSetupBenchmarks.cs | Adds benchmark comparing generated harness bootstrap projection vs runtime fallback. |
| FastMoq.Benchmarks/FastMoq.Benchmarks.csproj | References generator as analyzer for benchmarks + adds Abstractions reference. |
| FastMoq.Analyzers/GeneratedTestTargetShapeRules.cs | Adds shared package-layout + target-shape rule model for analyzers/generators. |
| FastMoq.Analyzers/FastMoqAnalysisHelpers.cs | Adds package matrix computation helpers and supporting constants. |
| FastMoq.Analyzers/Analyzers/MissingHelperPackageAnalyzer.cs | Refactors to compilation-start analysis using the shared package matrix. |
| FastMoq.Analyzers.Tests/GlobalUsings.cs | Adds AwesomeAssertions global usings for analyzer/generator tests. |
| FastMoq.Analyzers.Tests/GeneratorPackageMatrixTests.cs | Adds tests for package layout classification (core-only/split/aggregate). |
| FastMoq.Analyzers.Tests/GeneratedHarnessSourceGeneratorTests.cs | Adds generator-driver + representative compilation/parity tests for harness generation. |
| FastMoq.Analyzers.Tests/FastMoq.Analyzers.Tests.csproj | Adds references needed for generator + package-matrix testing. |
| FastMoq.Analyzers.Tests/AnalyzerTestHelpers.cs | Extends test project builder to model more package-layout combinations (aggregate/web/db/azure). |
| FastMoq.Abstractions/Generators/FastMoqGeneratedTestTargetAttribute.cs | Adds the explicit opt-in attribute used to mark harness targets for generation. |
| FastMoq-Release.sln | Adds FastMoq.Generators to the release solution topology. |
| docs/roadmap/README.md | Updates roadmap narrative to reflect shipped generator MVP + #162 settings gate. |
| docs/roadmap/generator-roadmap.md | Updates generator roadmap baseline/status to reflect the new generator slice and sequencing. |
| docs/roadmap/generated-test-settings.md | New design doc capturing the intended shared generated-test settings contract for #162. |
| docs/benchmarks/results/generated-harness-setup-net8.md | New benchmark results doc for generated harness bootstrap projection. |
| docs/benchmarks/README.md | Documents how to run and where to find the generated harness benchmark results. |
| Directory.Packages.props | Removes FluentAssertions central package entry (tests now use AwesomeAssertions). |
* Expand generated scenario scaffold executors * Add generated shared setup scaffold hooks * Strengthen generated shared setup hook ordering test * Document generated scenario scaffold members * docs: align generator roadmap with current scope * Widen generated harness smoke test coverage (#165) * Widen generated harness smoke test coverage * Fix: Escape C# keywords in generated method invocations When component methods are named with C# keywords (e.g., @Class, @return), the unescaped IMethodSymbol.Name resulted in invalid emitted code like 'component.class()' instead of 'component.@Class()'. - Add EscapeIdentifierIfKeyword helper using SyntaxFacts.GetKeywordKind - Apply escaping in CreateGeneratedTestMethodModel to all method references - Add [Fact] test covering keyword methods (@Class, @interface, @return) Addresses code review comment on GeneratedHarnessSourceGenerator.cs * feat(generators): wire FastMoqGeneratedTestFramework MSBuild property into generator pipeline (#123 slice 2) (#166) Wire FastMoqGeneratedTestFramework MSBuild property into generator pipeline - Add CompilerVisibleProperty for FastMoqGeneratedTestFramework to generator csproj - Read build_property.FastMoqGeneratedTestFramework in incremental pipeline via AnalyzerConfigOptionsProvider - Combine frameworkSetting with targets pipeline; pass to EmitSource - When value is 'none' (case-insensitive), suppress xUnit smoke-test emission regardless of metadata - Add TestAnalyzerConfigOptionsProvider / TestAnalyzerConfigOptions nested helpers for test isolation - Add 3 new [Fact] tests covering none suppression, explicit xunit enable, and case-insensitive none Part of #123
Comment on lines
+494
to
+497
| private static void EmitSource(SourceProductionContext context, GeneratedHarnessTargetModel target, string frameworkSetting) | ||
| { | ||
| var emitXUnitSmokeTests = target.EmitXUnitSmokeTests && | ||
| !string.Equals(frameworkSetting, FrameworkSettingNone, StringComparison.OrdinalIgnoreCase); |
Comment on lines
+555
to
+574
| AppendIndentedLine(sourceBuilder, 2, "/// <summary>"); | ||
| AppendIndentedLine(sourceBuilder, 2, "/// Executes the generated arrange, act, assert, and verify scaffold synchronously."); | ||
| AppendIndentedLine(sourceBuilder, 2, "/// </summary>"); | ||
| AppendIndentedLine(sourceBuilder, 2, "public void ExecuteGeneratedScenarioScaffold() => CreateGeneratedScenarioScaffold().Execute();"); | ||
| AppendIndentedLine(sourceBuilder, 2, "/// <summary>"); | ||
| AppendIndentedLine(sourceBuilder, 2, "/// Executes the generated arrange, act, assert, and verify scaffold asynchronously."); | ||
| AppendIndentedLine(sourceBuilder, 2, "/// </summary>"); | ||
| AppendIndentedLine(sourceBuilder, 2, "/// <returns>A task that completes when the generated scaffold finishes running.</returns>"); | ||
| AppendIndentedLine(sourceBuilder, 2, "public global::System.Threading.Tasks.Task ExecuteGeneratedScenarioScaffoldAsync() => CreateGeneratedScenarioScaffold().ExecuteAsync();"); | ||
| AppendIndentedLine(sourceBuilder, 2, "/// <summary>"); | ||
| AppendIndentedLine(sourceBuilder, 2, "/// Executes the generated scaffold with an act phase that expects the specified exception type."); | ||
| AppendIndentedLine(sourceBuilder, 2, "/// </summary>"); | ||
| AppendIndentedLine(sourceBuilder, 2, "/// <typeparam name=\"TException\">The exception type expected from the generated act phase.</typeparam>"); | ||
| AppendIndentedLine(sourceBuilder, 2, "public void ExecuteGeneratedExpectedExceptionScenarioScaffold<TException>() where TException : global::System.Exception => CreateGeneratedExpectedExceptionScenarioScaffold<TException>().Execute();"); | ||
| AppendIndentedLine(sourceBuilder, 2, "/// <summary>"); | ||
| AppendIndentedLine(sourceBuilder, 2, "/// Executes the generated scaffold asynchronously with an act phase that expects the specified exception type."); | ||
| AppendIndentedLine(sourceBuilder, 2, "/// </summary>"); | ||
| AppendIndentedLine(sourceBuilder, 2, "/// <typeparam name=\"TException\">The exception type expected from the generated act phase.</typeparam>"); | ||
| AppendIndentedLine(sourceBuilder, 2, "/// <returns>A task that completes when the generated scaffold finishes running.</returns>"); | ||
| AppendIndentedLine(sourceBuilder, 2, "public global::System.Threading.Tasks.Task ExecuteGeneratedExpectedExceptionScenarioScaffoldAsync<TException>() where TException : global::System.Exception => CreateGeneratedExpectedExceptionScenarioScaffold<TException>().ExecuteAsync();"); |
| - `GeneratedHarnessSourceGenerator` currently hard-codes the target attribute metadata name, the `MockerTestBase<TComponent>` requirement, the generated metadata type name, the `ComponentConstructorParameterTypes` override, the auto-generated header, `#nullable enable`, the `.FastMoq.GeneratedHarness.g.cs` hint-name suffix, and the current xUnit-gated smoke-test naming and placeholder strategy. | ||
| - `GeneratedTestTargetShapeRule` and `FastMoqAnalysisHelpers` currently own the package matrix, target-shape list, required package per shape, default base type name, and default namespaces for each supported generated test shape. | ||
| - `Directory.Packages.props` currently carries `xunit` `2.9.3` and `xunit.runner.visualstudio` `3.0.2`, while the repo documentation remains framework-agnostic. That mixed baseline is one reason syntax targeting and runner or bootstrap targeting must stay separate settings. | ||
| - `FastMoq.Generators.csproj` does not currently declare `CompilerVisibleProperty`, `CompilerVisibleItemMetadata`, or any equivalent custom bridge for generated-test authoring settings. |
|
|
||
| JSON or `AdditionalFiles` manifests are explicitly deferred. They should only be introduced if the structured settings shape demonstrably outgrows practical MSBuild properties or simple semicolon-delimited list values. | ||
|
|
||
| Implementation note: although Roslyn analyzers and generators can observe `build_property.*` values through generated analyzer config, this repo does not currently expose any custom generated-test settings bridge in `FastMoq.Generators.csproj`. A future implementation slice must add the required compiler-visible-property or equivalent build plumbing before any custom settings can flow into analyzer or generator code. The current `#136` scaffold implementation and the first narrow `#123` smoke-test slice therefore consume the `#162` vocabulary as fixed generator-owned defaults rather than as user-configurable settings values. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Validation
Issue Links