feat(dummies): add OrNull for optional value and reference generators - #176
Merged
Conversation
.OrNull() wraps any IAny<T> into a generator that yields null about half the time and otherwise a value satisfying the upstream constraints — the dummy for an optional field. Two overloads cover value types (returning IAny<T?> over Nullable<T>) and reference types; they live in separate classes because a single OrNull constrained once to struct and once to class would collide. The null-versus-value decision draws from the wrapped generator's own random context, so a run stays reproducible and a null draw does not consume a value. Tests cover both cases, composition with As (an optional value object), seed reproducibility, and argument validation; the reproducibility batch gains a nullable draw. README notes the feature. Full suite green on both target legs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhPrBqngpiSwdsF4DWvNPw
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
Adds
.OrNull()to theDummiesDSL: it turns any generator into one that yieldsnullabout half the time and otherwise a value satisfying the upstream constraints — the dummy for an optional field.Type of change
Changes
.OrNull()extension overIAny<T>, in two overloads: value types (where T : struct, returningIAny<T?>overNullable<T>) and reference types (where T : class). They live in separate classes (NullableExtensions,NullableReferenceExtensions) because a singleOrNullconstrained once tostructand once toclasswould collide; at a call site exactly one applies, so.OrNull()reads uniformly on any generator.nulldraw does not consume a value from the wrapped generator..OrNull()twice is a compile-time error by construction — aNullable<T>is neither a struct nor a class, so neither overload applies.AnyNullableTests(both overloads yield both cases and honour the inner constraints, composition withAsfor an optional value object, seed reproducibility, argument validation); the seed reproducibility batch gains a nullable draw.Testing
dotnet build FirstClassErrors.sln— succeeded, 0 warnings (bothnetstandard2.0andnet8.0legs).dotnet test FirstClassErrors.sln— all green (Dummies 150; FCE 423; Analyzers 85; GenDoc 155; PropertyTests 21; Binder 76; Cli 64).FirstClassErrors.Analyzers.UnitTests) — ran as part of the full suite above.Documentation
doc/updated —Dummies/README.nuget.md.doc/handwritten/for-users/README.fr.md) updated if user-facing behavior changedThe handwritten EN/FR user guides stay deferred until the V1 surface stabilizes (ADR-0011 follow-up); only the packaged NuGet readme is kept current here.
Architecture decisions
Proposed: ADR-____The 50/50 null rate is a deliberate, realism-free default (the library surfaces hidden dependencies rather than modelling how often a field is present); a probability-tuning overload was considered and intentionally left out to keep the API free of randomness knobs — addable later, non-breaking, if a concrete need appears.
🤖 Generated with Claude Code
Generated by Claude Code