Skip to content

Add opt-in nullability-aware null generation, fix null thresholds and date ranges - #4

Merged
holonsoftFounder merged 1 commit into
mainfrom
feature/nullable-annotations
Sep 9, 2026
Merged

holonsoftFounder merged 1 commit into
mainfrom
feature/nullable-annotations

Conversation

@holonsoftFounder

Copy link
Copy Markdown
Member

Feature: nullability-aware null generation (opt-in)

x.RespectNullableAnnotations(threshold) on the configuration builder. When enabled, every property or field declared as nullable (string?, int?, DateTime?, ...) gets its data source wrapped in a NullableMemberDataSource that returns null with the given probability (default AutoPocoGlobalSettings.NullCreationThreshold, 15 percent).

  • Covers convention sources, explicit Setup(...) sources and generation time Source(...) overrides.
  • Impose, non-nullable members, method parameters and members of types compiled without nullable annotations are never touched.
  • Each member gets its own deterministic seed (FNV-1a of the member key xor the standard seed), so the nullable members of one object do not all become null at once and two sessions of one factory produce the same pattern.
  • Plumbing: GenerationSessionFactory and GenerationConfiguration take optional NullableAnnotationSettings, exposed as IGenerationConfiguration.NullableAnnotations; ObjectBuilder wraps per member.
  • IDataSource<T> is covariant now, so .Setup(c => c.City).Use<CitySource>() compiles without a nullability warning for a string? member.

Bug fixes

  • Every Nullable* source ignored an explicit null creation threshold. The fixed array and dictionary sources even used it as the random seed. DataSourceBase got a protected constructor that installs the evaluator with the threshold; all nullable source bases use it. Null positions in the stable sequences of those sources changed, the data order did not.
  • DateTimeSource, DateOnlySource, TimeOnlySource, DateOfBirthSource: exclusive upper bounds (no December, no 31st, no 23:00, no :59, max year unreachable) and ranges within one year could yield values outside the range. All four pick uniformly from the inclusive range now, validate min <= max, TimeOnly wraps around midnight, DateTime keeps the kind of the minimum date. Sequences for a given seed changed.
  • RandomUtfTextSource looped forever when it hit a Unicode block without allowed characters (found by the new theory that draws 30 values per source).

Verification

  • dotnet build -c Release: zero warnings on net8/9/10.
  • dotnet test: 683 runs per framework, all green on net8.0, net9.0, net10.0 (Windows) and net10.0 on Linux (mcr.microsoft.com/dotnet/sdk:10.0 container).
  • README "New in 6.0.0" and PackageReleaseNotes updated.

🤖 Generated with Claude Code

… date ranges

Feature: x.RespectNullableAnnotations(threshold) on the configuration builder.
When enabled, every property or field declared as nullable (NRT annotation or
Nullable<T>) gets its data source wrapped in a NullableMemberDataSource that
returns null with the given probability. Each member gets its own deterministic
seed so the nullable members of an object do not become null together. Covers
conventions, explicit Setup(...) sources and generation time Source(...)
overrides; Impose and oblivious members are never touched. Plumbed through
GenerationSessionFactory, GenerationConfiguration (IGenerationConfiguration
.NullableAnnotations) and ObjectBuilder. IDataSource<T> is covariant now so a
source of string serves a string? member without a nullability warning.

Bug fixes:
- Every Nullable* source ignored an explicit null creation threshold; the fixed
  array and dictionary sources used it as the random seed. DataSourceBase got a
  protected constructor that installs the evaluator with the threshold, all
  nullable source bases use it. Null positions of the stable sequences changed,
  the data order did not.
- DateTimeSource, DateOnlySource, TimeOnlySource and DateOfBirthSource used
  exclusive upper bounds (no December, no 31st, no 23:00, no :59, no max year)
  and could leave a range that lies within one year. They now pick uniformly
  from the inclusive range, validate min <= max, TimeOnly wraps around midnight
  and DateTime keeps the kind of the minimum date. Sequences changed.
- RandomUtfTextSource looped forever on a Unicode block without allowed
  characters.

Tests: 683 runs per framework on net8/9/10, new suites for the helper, the
decorator, the settings, the integration behavior, a theory over all Nullable*
sources and range coverage tests for the date sources.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@holonsoftFounder
holonsoftFounder merged commit 8df8534 into main Sep 9, 2026
2 checks passed
@holonsoftFounder
holonsoftFounder deleted the feature/nullable-annotations branch September 9, 2026 06:01
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