feat(nsubstitute): milestone 5 phase 2 - test suites and verification - #30
Merged
Merged
Conversation
Adds Compono.NSubstitute.Tests (IsSubstitutable/NSubstituteProvider/ UseNSubstitute coverage, shared-substitute reuse via CompositionRow, and a public-API-surface approval test) and a real packaged end-to-end run through Compono.XunitV3.SampleTests proving the plan's own Goal scenario compiles and passes under a real xUnit v3 runner. Writing this phase's own regression coverage caught two real bugs before they shipped further: - NSubstituteProvider.IsSubstitutable misclassified System.Delegate/ System.MulticastDelegate themselves as substitutable abstract classes - ADR-0025 Amendment 1's stated intent was only half-enforced. - Compono.Generators' root-level CMP0003 check still hard-rejected an interface/abstract-class/delegate type used as a composed root, a stale pre-Milestone-5 assumption that broke this plan's own Goal snippet when actually compiled. Loosened per ADR-0024 Amendment 2, with generator regression coverage proving concrete-type roots are unaffected. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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
Implements PLAN-0005 Phase 2: test coverage for
Compono.NSubstitute(Phase 0/1's engine extension point and provider package) and a real, packaged end-to-end verification. Writing this phase's own regression coverage caught two real bugs in already-merged Phase 1/Milestone-1 code, both fixed here with their own regression tests.📝 Changes
test/Compono.NSubstitute.Tests(new project, 23 tests × 2 TFMs)IsSubstitutableTests.cs— direct coverage ofNSubstituteProvider.IsSubstitutable(interface / delegate / abstract-class with the option on and off / sealed class / struct /string), including theSystem.Delegate/System.MulticastDelegatenegative cases ADR-0025 Amendment 1 calls out.NSubstituteProviderTests.cs—TryProvide's outcome exercised through a realComposer(CompositionProviderResult'sValue/IsHandledare internal toCompono, so this is the only way to observe it from outside), plus the options-mutation snapshot regression test.CompositionBuilderExtensionsTests.cs—UseNSubstitute()/UseNSubstitute(configure)wiring a working provider into a realComposer.EndToEndCompositionTests.cs— the plan's own[Shared]-via-CompositionRowreuse shape, run against the realNSubstituteProvider.PublicApiSurfaceTests.cs— locksCompono.NSubstitute's exact public type set, matchingCompono.XunitV3.Tests' existing pattern.Real end-to-end verification (
test/Compono.XunitV3.SampleTests)Compono.NSubstitutepackage reference (packed from current source viapack-to-local-feed.sh, not aProjectReference) andNSubstituteTests.cs, running the plan's own Goal-section scenario verbatim under a real xUnit v3 runner.Two real bugs found and fixed while writing this phase's tests:
NSubstituteProvider.IsSubstitutablemisclassifiedSystem.Delegate/System.MulticastDelegatethemselves as substitutable abstract classes — ADR-0025 Amendment 1's stated intent was only half-enforced. Fixed by excludingtypeof(Delegate).IsAssignableFrom(requestedType)from the abstract-class branch.CMP0003compile error on the plan's own Goal snippet ([Shared] IOrderRepositoryas a bare xUnit theory parameter):Compono.Generators'LeafTypeClassifier.IsRuntimeProviderResolvedstill hard-rejected an interface/abstract-class/delegate root, a stale pre-Milestone-5 assumption from before public providers existed. Loosened to match the member-level classification (ADR-0024 Amendment 2), with four rewritten and one newCompono.Generators.Testssnapshot test proving concrete-type roots are unaffected.Docs
docs/adr/0024-public-provider-extensibility-model.md— Amendment 2 records theCMP0003root-check change and why it ships as an ordinaryfix, notbreaking.docs/mvp.md,docs/public-api.md— Milestone 5 / NSubstitute Integration now say "implemented and test-covered/end-to-end verified."docs/plans/0005-milestone-5-nsubstitute-integration.md— Phase 2 checked off and closed out with a detailed Notes entry.🧪 Validation
dotnet build/dotnet test— 720/720 passing (Compono.Tests412,Compono.Generators.Tests168,Compono.XunitV3.Tests94,Compono.NSubstitute.Tests46, all ×2 TFMs), 0 warnings.dotnet testrun oftest/Compono.XunitV3.SampleTestsagainst packages packed fresh from current source (notProjectReference) —NSubstituteTests.Saves_orderpasses end-to-end.Delegate/MulticastDelegateframework base types vs. a real custom delegate type; abstract-class substitution with the option on/off; options-instance mutation after registration has no effect on an already-registered provider; a concrete sealed type with no accessible constructor still reportsCMP0002at a composed root (proving theCMP0003loosening is scoped correctly).💬 Notes for Reviewers
The
CMP0003change (item 2 above) is the part most worth a close look — it's a generator behavior change, not test-only, made after confirming the direction with the repo owner rather than unilaterally. It's additive (previously non-compiling code now compiles; nothing that compiled before changes meaning), so nobreakinglabel applied, per ADR-0024's own Alpha Compatibility Policy.PLAN-0005 Phase 3 (docs/cleanup) remains open as its own follow-up PR.